starpc 0.4.9 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/Makefile +1 -0
  2. package/README.md +20 -10
  3. package/dist/echo/client-test.d.ts +1 -0
  4. package/dist/echo/client-test.js +20 -18
  5. package/dist/echo/echo.pb.d.ts +165 -12
  6. package/dist/echo/echo.pb.js +61 -17
  7. package/dist/echo/server.d.ts +8 -4
  8. package/dist/echo/server.js +29 -37
  9. package/dist/rpcstream/rpcstream.d.ts +6 -6
  10. package/dist/rpcstream/rpcstream.js +92 -51
  11. package/dist/rpcstream/rpcstream.pb.d.ts +46 -1
  12. package/dist/rpcstream/rpcstream.pb.js +157 -9
  13. package/dist/srpc/client.d.ts +3 -4
  14. package/dist/srpc/client.js +12 -46
  15. package/dist/srpc/common-rpc.d.ts +3 -2
  16. package/dist/srpc/common-rpc.js +12 -0
  17. package/dist/srpc/definition.d.ts +3 -3
  18. package/dist/srpc/handler.d.ts +2 -3
  19. package/dist/srpc/handler.js +5 -22
  20. package/dist/srpc/index.d.ts +1 -1
  21. package/dist/srpc/index.js +1 -1
  22. package/dist/srpc/packet.js +0 -32
  23. package/dist/srpc/pushable.d.ts +2 -0
  24. package/dist/srpc/pushable.js +13 -0
  25. package/dist/srpc/rpcproto.pb.d.ts +13 -6
  26. package/dist/srpc/rpcproto.pb.js +95 -10
  27. package/dist/srpc/server.d.ts +1 -0
  28. package/dist/srpc/server.js +7 -0
  29. package/dist/srpc/ts-proto-rpc.d.ts +3 -4
  30. package/e2e/e2e.ts +4 -3
  31. package/e2e/e2e_test.go +24 -1
  32. package/echo/client-test.ts +23 -18
  33. package/echo/echo.pb.go +33 -20
  34. package/echo/echo.pb.ts +90 -34
  35. package/echo/echo.proto +4 -0
  36. package/echo/echo_srpc.pb.go +77 -0
  37. package/echo/server.go +18 -0
  38. package/echo/server.ts +47 -41
  39. package/integration/integration.go +1 -2
  40. package/integration/integration.ts +5 -1
  41. package/integration/integration_srpc.pb.go +139 -0
  42. package/package.json +5 -3
  43. package/patches/ts-proto+1.115.5.patch +1339 -0
  44. package/srpc/client.ts +16 -50
  45. package/srpc/common-rpc.ts +14 -2
  46. package/srpc/definition.ts +3 -3
  47. package/srpc/handler.ts +17 -34
  48. package/srpc/index.ts +1 -1
  49. package/srpc/muxed-conn.go +2 -2
  50. package/srpc/packet-rw.go +4 -6
  51. package/srpc/packet.ts +0 -33
  52. package/srpc/pushable.ts +17 -0
  53. package/srpc/rpcproto.pb.ts +122 -12
  54. package/srpc/server-pipe.go +2 -2
  55. package/srpc/server.go +2 -2
  56. package/srpc/server.ts +8 -0
  57. package/srpc/ts-proto-rpc.ts +4 -6
  58. package/srpc/websocket.go +2 -2
  59. package/dist/echo/sever.d.ts +0 -0
  60. package/dist/echo/sever.js +0 -1
  61. package/dist/srpc/observable-source.d.ts +0 -9
  62. package/dist/srpc/observable-source.js +0 -25
  63. package/echo/sever.ts +0 -0
  64. package/srpc/observable-source.ts +0 -40
@@ -6,10 +6,10 @@ export interface Definition {
6
6
  [id: string]: MethodDefinition<unknown, unknown>;
7
7
  };
8
8
  }
9
- export interface MethodDefinition<RequestType, ResponseType> {
9
+ export interface MethodDefinition<RequestT, ResponseT> {
10
10
  name: string;
11
- requestType: MessageDefinition<RequestType>;
11
+ requestType: MessageDefinition<RequestT>;
12
12
  requestStream: boolean;
13
- responseType: MessageDefinition<ResponseType>;
13
+ responseType: MessageDefinition<ResponseT>;
14
14
  responseStream: boolean;
15
15
  }
@@ -1,5 +1,4 @@
1
1
  import type { Sink, Source } from 'it-stream-types';
2
- import { Observable } from 'rxjs';
3
2
  import { Definition, MethodDefinition } from './definition.js';
4
3
  export declare type InvokeFn = (dataSource: Source<Uint8Array>, dataSink: Sink<Uint8Array>) => Promise<void>;
5
4
  export interface Handler {
@@ -18,7 +17,7 @@ export declare class StaticHandler implements Handler {
18
17
  getMethodIDs(): string[];
19
18
  lookupMethod(serviceID: string, methodID: string): Promise<InvokeFn | null>;
20
19
  }
21
- declare type MethodProto = ((request: unknown) => Promise<unknown>) | ((request: unknown) => Observable<unknown>) | ((request: Observable<unknown>) => Promise<unknown>) | ((request: Observable<unknown>) => Observable<unknown>);
22
- export declare function createInvokeFn(methodInfo: MethodDefinition<unknown, unknown>, methodProto: MethodProto): InvokeFn;
20
+ declare type MethodProto<R, O> = ((request: R) => Promise<O>) | ((request: R) => AsyncIterable<O>) | ((request: AsyncIterable<R>) => Promise<O>) | ((request: AsyncIterable<R>) => AsyncIterable<O>);
21
+ export declare function createInvokeFn<R, O>(methodInfo: MethodDefinition<R, O>, methodProto: MethodProto<R, O>): InvokeFn;
23
22
  export declare function createHandler(definition: Definition, impl: any): Handler;
24
23
  export {};
@@ -1,7 +1,7 @@
1
1
  import { pipe } from 'it-pipe';
2
2
  import { pushable } from 'it-pushable';
3
- import { from as observableFrom } from 'rxjs';
4
3
  import { buildDecodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
4
+ import { writeToPushable } from './pushable.js';
5
5
  // StaticHandler is a handler with a definition and implementation.
6
6
  export class StaticHandler {
7
7
  constructor(serviceID, methods) {
@@ -40,8 +40,8 @@ export function createInvokeFn(methodInfo, methodProto) {
40
40
  // build the request argument.
41
41
  let requestArg;
42
42
  if (methodInfo.requestStream) {
43
- // convert the request data source into an Observable<T>
44
- requestArg = observableFrom(requestSource);
43
+ // use the request source as the argument.
44
+ requestArg = requestSource;
45
45
  }
46
46
  else {
47
47
  // receive a single message for the argument.
@@ -62,25 +62,8 @@ export function createInvokeFn(methodInfo, methodProto) {
62
62
  throw new Error('return value was undefined');
63
63
  }
64
64
  if (methodInfo.responseStream) {
65
- const responseObs = responseObj;
66
- if (!responseObs.subscribe) {
67
- throw new Error('expected return value to be an Observable');
68
- }
69
- return new Promise((resolve, reject) => {
70
- responseObs.subscribe({
71
- next(value) {
72
- responseSink.push(value);
73
- },
74
- error: (err) => {
75
- responseSink.throw(err);
76
- reject(err);
77
- },
78
- complete: () => {
79
- responseSink.end();
80
- resolve();
81
- },
82
- });
83
- });
65
+ const response = responseObj;
66
+ return writeToPushable(response, responseSink);
84
67
  }
85
68
  else {
86
69
  const responsePromise = responseObj;
@@ -7,4 +7,4 @@ export { Packet, CallStart, CallData } from './rpcproto.pb.js';
7
7
  export { Mux, createMux } from './mux.js';
8
8
  export { BroadcastChannelDuplex, newBroadcastChannelDuplex, BroadcastChannelConn, } from './broadcast-channel.js';
9
9
  export { MessagePortIterable, newMessagePortIterable, MessagePortConn, } from './message-port.js';
10
- export { ObservableSource } from './observable-source.js';
10
+ export { writeToPushable } from './pushable';
@@ -6,4 +6,4 @@ export { Packet, CallStart, CallData } from './rpcproto.pb.js';
6
6
  export { createMux } from './mux.js';
7
7
  export { BroadcastChannelDuplex, newBroadcastChannelDuplex, BroadcastChannelConn, } from './broadcast-channel.js';
8
8
  export { MessagePortIterable, newMessagePortIterable, MessagePortConn, } from './message-port.js';
9
- export { ObservableSource } from './observable-source.js';
9
+ export { writeToPushable } from './pushable';
@@ -66,35 +66,3 @@ export function prependPacketLen(msgData) {
66
66
  merged.set(msgData, msgLenData.length);
67
67
  return merged;
68
68
  }
69
- /*
70
- // buildCallDataPacket builds a CallData packet.
71
- function buildCallDataPacket(data: Uint8Array): Packet {
72
- const callData: CallData = {
73
- data: p,
74
- complete: false,
75
- error: '',
76
- }
77
- const pkt: Packet = {
78
- body: {
79
- $case: 'callData',
80
- callData: callData,
81
- }
82
- }
83
- return pkt
84
- }
85
-
86
- // wrapCallDataTransform is a transformer that wraps call data into a Packet.
87
- export async function* wrapCallDataTransform(
88
- source: Source<Uint8Array | Uint8Array>
89
- ): AsyncIterable<Packet> {
90
- for await (const pkt of source) {
91
- if (Array.isArray(pkt)) {
92
- for (const p of pkt) {
93
- yield* [buildCallDataPacket(p)]
94
- }
95
- } else {
96
- yield* [buildCallDataPacket(pkt)]
97
- }
98
- }
99
- }
100
- */
@@ -0,0 +1,2 @@
1
+ import { Pushable } from 'it-pushable';
2
+ export declare function writeToPushable<T>(dataSource: AsyncIterable<T>, out: Pushable<T>): Promise<void>;
@@ -0,0 +1,13 @@
1
+ // writeToPushable writes the incoming server data to the pushable.
2
+ export async function writeToPushable(dataSource, out) {
3
+ try {
4
+ for await (const data of dataSource) {
5
+ out.push(data);
6
+ }
7
+ out.end();
8
+ }
9
+ catch (err) {
10
+ out.end(err);
11
+ throw err;
12
+ }
13
+ }
@@ -1,14 +1,15 @@
1
1
  import Long from 'long';
2
2
  import * as _m0 from 'protobufjs/minimal';
3
+ import { CallStart as CallStart1, CallData as CallData2 } from './rpcproto.pb.js';
3
4
  export declare const protobufPackage = "srpc";
4
5
  /** Packet is a message sent over a srpc packet connection. */
5
6
  export interface Packet {
6
7
  body?: {
7
8
  $case: 'callStart';
8
- callStart: CallStart;
9
+ callStart: CallStart1;
9
10
  } | {
10
11
  $case: 'callData';
11
- callData: CallData;
12
+ callData: CallData2;
12
13
  };
13
14
  }
14
15
  /** CallStart requests starting a new RPC call. */
@@ -48,6 +49,8 @@ export interface CallData {
48
49
  export declare const Packet: {
49
50
  encode(message: Packet, writer?: _m0.Writer): _m0.Writer;
50
51
  decode(input: _m0.Reader | Uint8Array, length?: number): Packet;
52
+ encodeTransform(source: AsyncIterable<Packet | Packet[]> | Iterable<Packet | Packet[]>): AsyncIterable<Uint8Array>;
53
+ decodeTransform(source: AsyncIterable<Uint8Array | Uint8Array[]> | Iterable<Uint8Array | Uint8Array[]>): AsyncIterable<Packet>;
51
54
  fromJSON(object: any): Packet;
52
55
  toJSON(message: Packet): unknown;
53
56
  fromPartial<I extends {
@@ -91,7 +94,7 @@ export declare const Packet: {
91
94
  rpcMethod?: string | undefined;
92
95
  data?: Uint8Array | undefined;
93
96
  dataIsZero?: boolean | undefined;
94
- } & Record<Exclude<keyof I["body"]["callStart"], keyof CallStart>, never>) | undefined;
97
+ } & Record<Exclude<keyof I["body"]["callStart"], keyof CallStart1>, never>) | undefined;
95
98
  $case: "callStart";
96
99
  } & Record<Exclude<keyof I["body"], "callStart" | "$case">, never>) | ({
97
100
  callData?: {
@@ -113,7 +116,7 @@ export declare const Packet: {
113
116
  dataIsZero?: boolean | undefined;
114
117
  complete?: boolean | undefined;
115
118
  error?: string | undefined;
116
- } & Record<Exclude<keyof I["body"]["callData"], keyof CallData>, never>) | undefined;
119
+ } & Record<Exclude<keyof I["body"]["callData"], keyof CallData2>, never>) | undefined;
117
120
  $case: "callData";
118
121
  } & Record<Exclude<keyof I["body"], "callData" | "$case">, never>) | undefined;
119
122
  } & Record<Exclude<keyof I, "body">, never>>(object: I): Packet;
@@ -121,6 +124,8 @@ export declare const Packet: {
121
124
  export declare const CallStart: {
122
125
  encode(message: CallStart, writer?: _m0.Writer): _m0.Writer;
123
126
  decode(input: _m0.Reader | Uint8Array, length?: number): CallStart;
127
+ encodeTransform(source: AsyncIterable<CallStart | CallStart[]> | Iterable<CallStart | CallStart[]>): AsyncIterable<Uint8Array>;
128
+ decodeTransform(source: AsyncIterable<Uint8Array | Uint8Array[]> | Iterable<Uint8Array | Uint8Array[]>): AsyncIterable<CallStart>;
124
129
  fromJSON(object: any): CallStart;
125
130
  toJSON(message: CallStart): unknown;
126
131
  fromPartial<I extends {
@@ -133,11 +138,13 @@ export declare const CallStart: {
133
138
  rpcMethod?: string | undefined;
134
139
  data?: Uint8Array | undefined;
135
140
  dataIsZero?: boolean | undefined;
136
- } & Record<Exclude<keyof I, keyof CallStart>, never>>(object: I): CallStart;
141
+ } & Record<Exclude<keyof I, keyof CallStart1>, never>>(object: I): CallStart;
137
142
  };
138
143
  export declare const CallData: {
139
144
  encode(message: CallData, writer?: _m0.Writer): _m0.Writer;
140
145
  decode(input: _m0.Reader | Uint8Array, length?: number): CallData;
146
+ encodeTransform(source: AsyncIterable<CallData | CallData[]> | Iterable<CallData | CallData[]>): AsyncIterable<Uint8Array>;
147
+ decodeTransform(source: AsyncIterable<Uint8Array | Uint8Array[]> | Iterable<Uint8Array | Uint8Array[]>): AsyncIterable<CallData>;
141
148
  fromJSON(object: any): CallData;
142
149
  toJSON(message: CallData): unknown;
143
150
  fromPartial<I extends {
@@ -150,7 +157,7 @@ export declare const CallData: {
150
157
  dataIsZero?: boolean | undefined;
151
158
  complete?: boolean | undefined;
152
159
  error?: string | undefined;
153
- } & Record<Exclude<keyof I, keyof CallData>, never>>(object: I): CallData;
160
+ } & Record<Exclude<keyof I, keyof CallData2>, never>>(object: I): CallData;
154
161
  };
155
162
  declare type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
156
163
  export declare type DeepPartial<T> = T extends Builtin ? T : T extends Long ? string | number | Long : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable */
2
2
  import Long from 'long';
3
3
  import * as _m0 from 'protobufjs/minimal';
4
+ import { CallStart as CallStart1, CallData as CallData2, } from './rpcproto.pb.js';
4
5
  export const protobufPackage = 'srpc';
5
6
  function createBasePacket() {
6
7
  return { body: undefined };
@@ -8,10 +9,10 @@ function createBasePacket() {
8
9
  export const Packet = {
9
10
  encode(message, writer = _m0.Writer.create()) {
10
11
  if (message.body?.$case === 'callStart') {
11
- CallStart.encode(message.body.callStart, writer.uint32(10).fork()).ldelim();
12
+ CallStart1.encode(message.body.callStart, writer.uint32(10).fork()).ldelim();
12
13
  }
13
14
  if (message.body?.$case === 'callData') {
14
- CallData.encode(message.body.callData, writer.uint32(18).fork()).ldelim();
15
+ CallData2.encode(message.body.callData, writer.uint32(18).fork()).ldelim();
15
16
  }
16
17
  return writer;
17
18
  },
@@ -25,13 +26,13 @@ export const Packet = {
25
26
  case 1:
26
27
  message.body = {
27
28
  $case: 'callStart',
28
- callStart: CallStart.decode(reader, reader.uint32()),
29
+ callStart: CallStart1.decode(reader, reader.uint32()),
29
30
  };
30
31
  break;
31
32
  case 2:
32
33
  message.body = {
33
34
  $case: 'callData',
34
- callData: CallData.decode(reader, reader.uint32()),
35
+ callData: CallData2.decode(reader, reader.uint32()),
35
36
  };
36
37
  break;
37
38
  default:
@@ -41,15 +42,43 @@ export const Packet = {
41
42
  }
42
43
  return message;
43
44
  },
45
+ // encodeTransform encodes a source of message objects.
46
+ // Transform<Packet, Uint8Array>
47
+ async *encodeTransform(source) {
48
+ for await (const pkt of source) {
49
+ if (Array.isArray(pkt)) {
50
+ for (const p of pkt) {
51
+ yield* [Packet.encode(p).finish()];
52
+ }
53
+ }
54
+ else {
55
+ yield* [Packet.encode(pkt).finish()];
56
+ }
57
+ }
58
+ },
59
+ // decodeTransform decodes a source of encoded messages.
60
+ // Transform<Uint8Array, Packet>
61
+ async *decodeTransform(source) {
62
+ for await (const pkt of source) {
63
+ if (Array.isArray(pkt)) {
64
+ for (const p of pkt) {
65
+ yield* [Packet.decode(p)];
66
+ }
67
+ }
68
+ else {
69
+ yield* [Packet.decode(pkt)];
70
+ }
71
+ }
72
+ },
44
73
  fromJSON(object) {
45
74
  return {
46
75
  body: isSet(object.callStart)
47
76
  ? {
48
77
  $case: 'callStart',
49
- callStart: CallStart.fromJSON(object.callStart),
78
+ callStart: CallStart1.fromJSON(object.callStart),
50
79
  }
51
80
  : isSet(object.callData)
52
- ? { $case: 'callData', callData: CallData.fromJSON(object.callData) }
81
+ ? { $case: 'callData', callData: CallData2.fromJSON(object.callData) }
53
82
  : undefined,
54
83
  };
55
84
  },
@@ -57,11 +86,11 @@ export const Packet = {
57
86
  const obj = {};
58
87
  message.body?.$case === 'callStart' &&
59
88
  (obj.callStart = message.body?.callStart
60
- ? CallStart.toJSON(message.body?.callStart)
89
+ ? CallStart1.toJSON(message.body?.callStart)
61
90
  : undefined);
62
91
  message.body?.$case === 'callData' &&
63
92
  (obj.callData = message.body?.callData
64
- ? CallData.toJSON(message.body?.callData)
93
+ ? CallData2.toJSON(message.body?.callData)
65
94
  : undefined);
66
95
  return obj;
67
96
  },
@@ -72,7 +101,7 @@ export const Packet = {
72
101
  object.body?.callStart !== null) {
73
102
  message.body = {
74
103
  $case: 'callStart',
75
- callStart: CallStart.fromPartial(object.body.callStart),
104
+ callStart: CallStart1.fromPartial(object.body.callStart),
76
105
  };
77
106
  }
78
107
  if (object.body?.$case === 'callData' &&
@@ -80,7 +109,7 @@ export const Packet = {
80
109
  object.body?.callData !== null) {
81
110
  message.body = {
82
111
  $case: 'callData',
83
- callData: CallData.fromPartial(object.body.callData),
112
+ callData: CallData2.fromPartial(object.body.callData),
84
113
  };
85
114
  }
86
115
  return message;
@@ -136,6 +165,34 @@ export const CallStart = {
136
165
  }
137
166
  return message;
138
167
  },
168
+ // encodeTransform encodes a source of message objects.
169
+ // Transform<CallStart, Uint8Array>
170
+ async *encodeTransform(source) {
171
+ for await (const pkt of source) {
172
+ if (Array.isArray(pkt)) {
173
+ for (const p of pkt) {
174
+ yield* [CallStart.encode(p).finish()];
175
+ }
176
+ }
177
+ else {
178
+ yield* [CallStart.encode(pkt).finish()];
179
+ }
180
+ }
181
+ },
182
+ // decodeTransform decodes a source of encoded messages.
183
+ // Transform<Uint8Array, CallStart>
184
+ async *decodeTransform(source) {
185
+ for await (const pkt of source) {
186
+ if (Array.isArray(pkt)) {
187
+ for (const p of pkt) {
188
+ yield* [CallStart.decode(p)];
189
+ }
190
+ }
191
+ else {
192
+ yield* [CallStart.decode(pkt)];
193
+ }
194
+ }
195
+ },
139
196
  fromJSON(object) {
140
197
  return {
141
198
  rpcService: isSet(object.rpcService) ? String(object.rpcService) : '',
@@ -214,6 +271,34 @@ export const CallData = {
214
271
  }
215
272
  return message;
216
273
  },
274
+ // encodeTransform encodes a source of message objects.
275
+ // Transform<CallData, Uint8Array>
276
+ async *encodeTransform(source) {
277
+ for await (const pkt of source) {
278
+ if (Array.isArray(pkt)) {
279
+ for (const p of pkt) {
280
+ yield* [CallData.encode(p).finish()];
281
+ }
282
+ }
283
+ else {
284
+ yield* [CallData.encode(pkt).finish()];
285
+ }
286
+ }
287
+ },
288
+ // decodeTransform decodes a source of encoded messages.
289
+ // Transform<Uint8Array, CallData>
290
+ async *decodeTransform(source) {
291
+ for await (const pkt of source) {
292
+ if (Array.isArray(pkt)) {
293
+ for (const p of pkt) {
294
+ yield* [CallData.decode(p)];
295
+ }
296
+ }
297
+ else {
298
+ yield* [CallData.decode(pkt)];
299
+ }
300
+ }
301
+ },
217
302
  fromJSON(object) {
218
303
  return {
219
304
  data: isSet(object.data)
@@ -10,5 +10,6 @@ export declare class Server implements StreamHandler {
10
10
  startRpc(): ServerRPC;
11
11
  handleStream(stream: Stream): ServerRPC;
12
12
  handleDuplex(stream: Duplex<Uint8Array>): ServerRPC;
13
+ handlePacketDuplex(stream: Duplex<Uint8Array>): ServerRPC;
13
14
  handlePacketStream(stream: Duplex<Packet>): ServerRPC;
14
15
  }
@@ -21,6 +21,13 @@ export class Server {
21
21
  pipe(stream, parseLengthPrefixTransform(), decodePacketSource, rpc, encodePacketSource, prependLengthPrefixTransform(), stream);
22
22
  return rpc;
23
23
  }
24
+ // handlePacketDuplex handles an incoming Uint8Array duplex.
25
+ // skips the packet length prefix transform.
26
+ handlePacketDuplex(stream) {
27
+ const rpc = this.startRpc();
28
+ pipe(stream, decodePacketSource, rpc, encodePacketSource, stream);
29
+ return rpc;
30
+ }
24
31
  // handlePacketStream handles an incoming Packet duplex.
25
32
  handlePacketStream(stream) {
26
33
  const rpc = this.startRpc();
@@ -1,7 +1,6 @@
1
- import type { Observable } from 'rxjs';
2
1
  export interface TsProtoRpc {
3
2
  request(service: string, method: string, data: Uint8Array): Promise<Uint8Array>;
4
- clientStreamingRequest(service: string, method: string, data: Observable<Uint8Array>): Promise<Uint8Array>;
5
- serverStreamingRequest(service: string, method: string, data: Uint8Array): Observable<Uint8Array>;
6
- bidirectionalStreamingRequest(service: string, method: string, data: Observable<Uint8Array>): Observable<Uint8Array>;
3
+ clientStreamingRequest(service: string, method: string, data: AsyncIterable<Uint8Array>): Promise<Uint8Array>;
4
+ serverStreamingRequest(service: string, method: string, data: Uint8Array): AsyncIterable<Uint8Array>;
5
+ bidirectionalStreamingRequest(service: string, method: string, data: AsyncIterable<Uint8Array>): AsyncIterable<Uint8Array>;
7
6
  }
package/e2e/e2e.ts CHANGED
@@ -1,18 +1,20 @@
1
1
  import { pipe } from 'it-pipe'
2
2
  import { createHandler, createMux, Server, Client, Conn } from '../srpc'
3
3
  import { EchoerDefinition, EchoerServer, runClientTest } from '../echo'
4
+ import { runRpcStreamTest } from '../echo/client-test'
4
5
 
5
6
  async function runRPC() {
6
7
  const mux = createMux()
7
- const echoer = new EchoerServer()
8
- mux.register(createHandler(EchoerDefinition, echoer))
9
8
  const server = new Server(mux)
9
+ const echoer = new EchoerServer(server)
10
+ mux.register(createHandler(EchoerDefinition, echoer))
10
11
 
11
12
  const clientConn = new Conn()
12
13
  const serverConn = new Conn(server)
13
14
  pipe(clientConn, serverConn, clientConn)
14
15
  const client = new Client(clientConn.buildOpenStreamFunc())
15
16
 
17
+ await runRpcStreamTest(client)
16
18
  await runClientTest(client)
17
19
  }
18
20
 
@@ -21,7 +23,6 @@ runRPC()
21
23
  console.log('finished successfully')
22
24
  })
23
25
  .catch((err) => {
24
- console.log('failed')
25
26
  console.error(err)
26
27
  process.exit(1)
27
28
  })
package/e2e/e2e_test.go CHANGED
@@ -8,6 +8,7 @@ import (
8
8
  "time"
9
9
 
10
10
  "github.com/aperturerobotics/starpc/echo"
11
+ "github.com/aperturerobotics/starpc/rpcstream"
11
12
  "github.com/aperturerobotics/starpc/srpc"
12
13
  "github.com/libp2p/go-libp2p/p2p/muxer/mplex"
13
14
  mp "github.com/libp2p/go-mplex"
@@ -17,8 +18,8 @@ import (
17
18
  // RunE2E runs an end to end test with a callback.
18
19
  func RunE2E(t *testing.T, cb func(client echo.SRPCEchoerClient) error) {
19
20
  // construct the server
20
- echoServer := &echo.EchoServer{}
21
21
  mux := srpc.NewMux()
22
+ echoServer := echo.NewEchoServer(mux)
22
23
  if err := echo.SRPCRegisterEchoer(mux, echoServer); err != nil {
23
24
  t.Fatal(err.Error())
24
25
  }
@@ -179,3 +180,25 @@ func TestE2E_BidiStream(t *testing.T) {
179
180
  return strm.Close()
180
181
  })
181
182
  }
183
+
184
+ func TestE2E_RpcStream(t *testing.T) {
185
+ ctx := context.Background()
186
+ RunE2E(t, func(client echo.SRPCEchoerClient) error {
187
+ openStreamFn := rpcstream.NewRpcStreamOpenStream(func(ctx context.Context) (rpcstream.RpcStream, error) {
188
+ return client.RpcStream(ctx)
189
+ }, "test")
190
+ proxiedClient := srpc.NewClient(openStreamFn)
191
+ proxiedSvc := echo.NewSRPCEchoerClient(proxiedClient)
192
+
193
+ // run a RPC proxied over another RPC
194
+ resp, err := proxiedSvc.Echo(ctx, &echo.EchoMsg{Body: "hello world"})
195
+ if err != nil {
196
+ return err
197
+ }
198
+ if resp.GetBody() != "hello world" {
199
+ return errors.Errorf("response body incorrect: %q", resp.GetBody())
200
+ }
201
+
202
+ return nil
203
+ })
204
+ }
@@ -1,6 +1,7 @@
1
1
  import { Client } from '../srpc/index.js'
2
2
  import { EchoerClientImpl, EchoMsg } from './echo.pb.js'
3
- import { Observable } from 'rxjs'
3
+ import { pushable } from 'it-pushable'
4
+ import { buildRpcStreamOpenStream } from '../rpcstream/rpcstream.js'
4
5
 
5
6
  export async function runClientTest(client: Client) {
6
7
  const demoServiceClient = new EchoerClientImpl(client)
@@ -12,10 +13,9 @@ export async function runClientTest(client: Client) {
12
13
  console.log('success: output', result.body)
13
14
 
14
15
  // observable for client requests
15
- const clientRequestStream = new Observable<EchoMsg>((subscriber) => {
16
- subscriber.next({ body: 'Hello world from streaming request.' })
17
- subscriber.complete()
18
- })
16
+ const clientRequestStream = pushable<EchoMsg>({ objectMode: true })
17
+ clientRequestStream.push({ body: 'Hello world from streaming request.' })
18
+ clientRequestStream.end()
19
19
 
20
20
  console.log('Calling EchoClientStream: client -> server...')
21
21
  result = await demoServiceClient.EchoClientStream(clientRequestStream)
@@ -25,17 +25,22 @@ export async function runClientTest(client: Client) {
25
25
  const serverStream = demoServiceClient.EchoServerStream({
26
26
  body: 'Hello world from server to client streaming request.',
27
27
  })
28
- await new Promise<void>((resolve, reject) => {
29
- serverStream.subscribe({
30
- next(result) {
31
- console.log('server: output', result.body)
32
- },
33
- complete() {
34
- resolve()
35
- },
36
- error(err: Error) {
37
- reject(err)
38
- },
39
- })
40
- })
28
+ for await (const msg of serverStream) {
29
+ console.log('server: output', msg.body)
30
+ }
31
+ }
32
+
33
+ // runRpcStreamTest tests a RPCStream.
34
+ export async function runRpcStreamTest(client: Client) {
35
+ console.log('Calling RpcStream to open a RPC stream client...')
36
+ const service = new EchoerClientImpl(client)
37
+ const openStreamFn = buildRpcStreamOpenStream(
38
+ 'test',
39
+ service.RpcStream.bind(service)
40
+ )
41
+ const proxiedClient = new Client(openStreamFn)
42
+ const proxiedService = new EchoerClientImpl(proxiedClient)
43
+ console.log('Calling Echo via RPC stream...')
44
+ const resp = await proxiedService.Echo({ body: 'hello world via proxy' })
45
+ console.log('rpc stream test: succeeded: response: ' + resp.body)
41
46
  }