starpc 0.1.7 → 0.2.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 (73) hide show
  1. package/Makefile +1 -0
  2. package/README.md +24 -5
  3. package/dist/echo/client-test.d.ts +2 -0
  4. package/dist/echo/client-test.js +35 -0
  5. package/dist/echo/echo.d.ts +124 -0
  6. package/dist/echo/echo.js +42 -0
  7. package/dist/echo/index.d.ts +3 -0
  8. package/dist/echo/index.js +3 -0
  9. package/dist/echo/server.d.ts +8 -0
  10. package/dist/echo/server.js +50 -0
  11. package/dist/echo/sever.d.ts +0 -0
  12. package/dist/echo/sever.js +1 -0
  13. package/dist/srpc/broadcast-channel.d.ts +3 -2
  14. package/dist/srpc/broadcast-channel.js +2 -2
  15. package/dist/srpc/client-rpc.d.ts +4 -28
  16. package/dist/srpc/client-rpc.js +9 -152
  17. package/dist/srpc/client.d.ts +2 -2
  18. package/dist/srpc/client.js +56 -84
  19. package/dist/srpc/common-rpc.d.ts +24 -0
  20. package/dist/srpc/common-rpc.js +140 -0
  21. package/dist/srpc/conn.d.ts +8 -3
  22. package/dist/srpc/conn.js +19 -3
  23. package/dist/srpc/definition.d.ts +15 -0
  24. package/dist/srpc/definition.js +1 -0
  25. package/dist/srpc/handler.d.ts +24 -0
  26. package/dist/srpc/handler.js +123 -0
  27. package/dist/srpc/index.d.ts +7 -3
  28. package/dist/srpc/index.js +6 -2
  29. package/dist/srpc/message.d.ts +11 -0
  30. package/dist/srpc/message.js +32 -0
  31. package/dist/srpc/mux.d.ts +11 -0
  32. package/dist/srpc/mux.js +36 -0
  33. package/dist/srpc/packet.d.ts +4 -4
  34. package/dist/srpc/packet.js +38 -27
  35. package/dist/srpc/rpcproto.d.ts +18 -43
  36. package/dist/srpc/rpcproto.js +37 -78
  37. package/dist/srpc/server-rpc.d.ts +11 -0
  38. package/dist/srpc/server-rpc.js +55 -0
  39. package/dist/srpc/server.d.ts +14 -0
  40. package/dist/srpc/server.js +31 -0
  41. package/dist/srpc/websocket.d.ts +3 -2
  42. package/dist/srpc/websocket.js +4 -4
  43. package/e2e/README.md +10 -0
  44. package/e2e/e2e.ts +27 -0
  45. package/echo/client-test.ts +41 -0
  46. package/echo/echo.ts +45 -0
  47. package/echo/index.ts +3 -0
  48. package/echo/server.ts +57 -0
  49. package/echo/sever.ts +0 -0
  50. package/integration/integration.bash +1 -1
  51. package/integration/integration.ts +10 -42
  52. package/package.json +18 -17
  53. package/srpc/broadcast-channel.ts +8 -3
  54. package/srpc/client-rpc.go +1 -9
  55. package/srpc/client-rpc.ts +11 -175
  56. package/srpc/client.ts +58 -99
  57. package/srpc/common-rpc.ts +171 -0
  58. package/srpc/conn.ts +33 -5
  59. package/srpc/definition.ts +30 -0
  60. package/srpc/handler.ts +174 -0
  61. package/srpc/index.ts +7 -3
  62. package/srpc/message.ts +60 -0
  63. package/srpc/mux.ts +56 -0
  64. package/srpc/packet.go +4 -11
  65. package/srpc/packet.ts +44 -30
  66. package/srpc/rpcproto.pb.go +54 -118
  67. package/srpc/rpcproto.proto +7 -12
  68. package/srpc/rpcproto.ts +38 -101
  69. package/srpc/rpcproto_vtproto.pb.go +58 -210
  70. package/srpc/server-rpc.go +5 -10
  71. package/srpc/server-rpc.ts +65 -0
  72. package/srpc/server.ts +56 -0
  73. package/srpc/websocket.ts +6 -4
@@ -0,0 +1,36 @@
1
+ // createMux builds a new Mux.
2
+ export function createMux() {
3
+ return new StaticMux();
4
+ }
5
+ // StaticMux contains a in-memory mapping between service ID and handlers.
6
+ // implements Mux
7
+ export class StaticMux {
8
+ // services contains a mapping from service id to handlers.
9
+ services = {};
10
+ register(handler) {
11
+ const serviceID = handler?.getServiceID();
12
+ if (!serviceID) {
13
+ throw new Error('service id cannot be empty');
14
+ }
15
+ const serviceMethods = this.services[serviceID] || {};
16
+ const methodIDs = handler.getMethodIDs();
17
+ for (const methodID of methodIDs) {
18
+ serviceMethods[methodID] = handler;
19
+ }
20
+ this.services[serviceID] = serviceMethods;
21
+ }
22
+ async lookupMethod(serviceID, methodID) {
23
+ if (!serviceID) {
24
+ return null;
25
+ }
26
+ const serviceMethods = this.services[serviceID];
27
+ if (!serviceMethods) {
28
+ return null;
29
+ }
30
+ const handler = serviceMethods[methodID];
31
+ if (!handler) {
32
+ return null;
33
+ }
34
+ return await handler.lookupMethod(serviceID, methodID);
35
+ }
36
+ }
@@ -1,7 +1,7 @@
1
- import type { Source, Transform } from 'it-stream-types';
2
- import { Packet } from './rpcproto';
3
- export declare function decodePacketSource(source: Source<Uint8Array | Uint8Array[]>): AsyncIterable<Packet>;
4
- export declare function encodePacketSource(source: Source<Packet | Packet[]>): AsyncIterable<Uint8Array>;
1
+ import type { Transform } from 'it-stream-types';
2
+ import { Packet } from './rpcproto.js';
3
+ export declare const decodePacketSource: (source: import("it-stream-types").Source<Uint8Array | Uint8Array[]>) => AsyncIterable<Packet>;
4
+ export declare const encodePacketSource: (source: import("it-stream-types").Source<Packet | Packet[]>) => AsyncIterable<Uint8Array>;
5
5
  export declare function prependLengthPrefixTransform(): Transform<Uint8Array>;
6
6
  export declare function parseLengthPrefixTransform(): Transform<Uint8Array>;
7
7
  export declare function encodeUint32Le(value: number): Uint8Array;
@@ -1,31 +1,10 @@
1
- import { Packet } from './rpcproto';
2
1
  import { encode as lengthPrefixEncode, decode as lengthPrefixDecode, } from 'it-length-prefixed';
3
- // decodePacketSource unmarshals and async yields encoded Packets.
4
- export async function* decodePacketSource(source) {
5
- for await (const pkt of source) {
6
- if (Array.isArray(pkt)) {
7
- for (const p of pkt) {
8
- yield* [Packet.decode(p)];
9
- }
10
- }
11
- else {
12
- yield* [Packet.decode(pkt)];
13
- }
14
- }
15
- }
16
- // encodePacketSource marshals and async yields packets.
17
- export async function* encodePacketSource(source) {
18
- for await (const pkt of source) {
19
- if (Array.isArray(pkt)) {
20
- for (const p of pkt) {
21
- yield* [Packet.encode(p).finish()];
22
- }
23
- }
24
- else {
25
- yield* [Packet.encode(pkt).finish()];
26
- }
27
- }
28
- }
2
+ import { Packet } from './rpcproto.js';
3
+ import { buildDecodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
4
+ // decodePacketSource decodes packets from a binary data stream.
5
+ export const decodePacketSource = buildDecodeMessageTransform(Packet);
6
+ // encodePacketSource encodes packets from a packet object stream.
7
+ export const encodePacketSource = buildEncodeMessageTransform(Packet);
29
8
  // uint32LEDecode removes the length prefix.
30
9
  const uint32LEDecode = (data) => {
31
10
  if (data.length < 4) {
@@ -87,3 +66,35 @@ export function prependPacketLen(msgData) {
87
66
  merged.set(msgData, msgLenData.length);
88
67
  return merged;
89
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
+ */
@@ -6,9 +6,6 @@ export interface Packet {
6
6
  body?: {
7
7
  $case: 'callStart';
8
8
  callStart: CallStart;
9
- } | {
10
- $case: 'callStartResp';
11
- callStartResp: CallStartResp;
12
9
  } | {
13
10
  $case: 'callData';
14
11
  callData: CallData;
@@ -31,19 +28,15 @@ export interface CallStart {
31
28
  * Optional if streaming.
32
29
  */
33
30
  data: Uint8Array;
34
- }
35
- /** CallStartResp is the response to CallStart. */
36
- export interface CallStartResp {
37
- /**
38
- * Error contains any error starting the RPC call.
39
- * Empty if successful.
40
- */
41
- error: string;
31
+ /** DataIsZero indicates Data is set with an empty message. */
32
+ dataIsZero: boolean;
42
33
  }
43
34
  /** CallData contains a message in a streaming RPC sequence. */
44
35
  export interface CallData {
45
36
  /** Data contains the packet in the sequence. */
46
37
  data: Uint8Array;
38
+ /** DataIsZero indicates Data is set with an empty message. */
39
+ dataIsZero: boolean;
47
40
  /** Complete indicates the RPC call is completed. */
48
41
  complete: boolean;
49
42
  /**
@@ -63,18 +56,14 @@ export declare const Packet: {
63
56
  rpcService?: string | undefined;
64
57
  rpcMethod?: string | undefined;
65
58
  data?: Uint8Array | undefined;
59
+ dataIsZero?: boolean | undefined;
66
60
  } | undefined;
67
61
  } & {
68
62
  $case: "callStart";
69
- }) | ({
70
- callStartResp?: {
71
- error?: string | undefined;
72
- } | undefined;
73
- } & {
74
- $case: "callStartResp";
75
63
  }) | ({
76
64
  callData?: {
77
65
  data?: Uint8Array | undefined;
66
+ dataIsZero?: boolean | undefined;
78
67
  complete?: boolean | undefined;
79
68
  error?: string | undefined;
80
69
  } | undefined;
@@ -87,6 +76,7 @@ export declare const Packet: {
87
76
  rpcService?: string | undefined;
88
77
  rpcMethod?: string | undefined;
89
78
  data?: Uint8Array | undefined;
79
+ dataIsZero?: boolean | undefined;
90
80
  } | undefined;
91
81
  } & {
92
82
  $case: "callStart";
@@ -95,28 +85,18 @@ export declare const Packet: {
95
85
  rpcService?: string | undefined;
96
86
  rpcMethod?: string | undefined;
97
87
  data?: Uint8Array | undefined;
88
+ dataIsZero?: boolean | undefined;
98
89
  } & {
99
90
  rpcService?: string | undefined;
100
91
  rpcMethod?: string | undefined;
101
92
  data?: Uint8Array | undefined;
93
+ dataIsZero?: boolean | undefined;
102
94
  } & Record<Exclude<keyof I["body"]["callStart"], keyof CallStart>, never>) | undefined;
103
95
  $case: "callStart";
104
- } & Record<Exclude<keyof I["body"], "$case" | "callStart">, never>) | ({
105
- callStartResp?: {
106
- error?: string | undefined;
107
- } | undefined;
108
- } & {
109
- $case: "callStartResp";
110
- } & {
111
- callStartResp?: ({
112
- error?: string | undefined;
113
- } & {
114
- error?: string | undefined;
115
- } & Record<Exclude<keyof I["body"]["callStartResp"], "error">, never>) | undefined;
116
- $case: "callStartResp";
117
- } & Record<Exclude<keyof I["body"], "$case" | "callStartResp">, never>) | ({
96
+ } & Record<Exclude<keyof I["body"], "callStart" | "$case">, never>) | ({
118
97
  callData?: {
119
98
  data?: Uint8Array | undefined;
99
+ dataIsZero?: boolean | undefined;
120
100
  complete?: boolean | undefined;
121
101
  error?: string | undefined;
122
102
  } | undefined;
@@ -125,15 +105,17 @@ export declare const Packet: {
125
105
  } & {
126
106
  callData?: ({
127
107
  data?: Uint8Array | undefined;
108
+ dataIsZero?: boolean | undefined;
128
109
  complete?: boolean | undefined;
129
110
  error?: string | undefined;
130
111
  } & {
131
112
  data?: Uint8Array | undefined;
113
+ dataIsZero?: boolean | undefined;
132
114
  complete?: boolean | undefined;
133
115
  error?: string | undefined;
134
116
  } & Record<Exclude<keyof I["body"]["callData"], keyof CallData>, never>) | undefined;
135
117
  $case: "callData";
136
- } & Record<Exclude<keyof I["body"], "$case" | "callData">, never>) | undefined;
118
+ } & Record<Exclude<keyof I["body"], "callData" | "$case">, never>) | undefined;
137
119
  } & Record<Exclude<keyof I, "body">, never>>(object: I): Packet;
138
120
  };
139
121
  export declare const CallStart: {
@@ -145,23 +127,14 @@ export declare const CallStart: {
145
127
  rpcService?: string | undefined;
146
128
  rpcMethod?: string | undefined;
147
129
  data?: Uint8Array | undefined;
130
+ dataIsZero?: boolean | undefined;
148
131
  } & {
149
132
  rpcService?: string | undefined;
150
133
  rpcMethod?: string | undefined;
151
134
  data?: Uint8Array | undefined;
135
+ dataIsZero?: boolean | undefined;
152
136
  } & Record<Exclude<keyof I, keyof CallStart>, never>>(object: I): CallStart;
153
137
  };
154
- export declare const CallStartResp: {
155
- encode(message: CallStartResp, writer?: _m0.Writer): _m0.Writer;
156
- decode(input: _m0.Reader | Uint8Array, length?: number): CallStartResp;
157
- fromJSON(object: any): CallStartResp;
158
- toJSON(message: CallStartResp): unknown;
159
- fromPartial<I extends {
160
- error?: string | undefined;
161
- } & {
162
- error?: string | undefined;
163
- } & Record<Exclude<keyof I, "error">, never>>(object: I): CallStartResp;
164
- };
165
138
  export declare const CallData: {
166
139
  encode(message: CallData, writer?: _m0.Writer): _m0.Writer;
167
140
  decode(input: _m0.Reader | Uint8Array, length?: number): CallData;
@@ -169,10 +142,12 @@ export declare const CallData: {
169
142
  toJSON(message: CallData): unknown;
170
143
  fromPartial<I extends {
171
144
  data?: Uint8Array | undefined;
145
+ dataIsZero?: boolean | undefined;
172
146
  complete?: boolean | undefined;
173
147
  error?: string | undefined;
174
148
  } & {
175
149
  data?: Uint8Array | undefined;
150
+ dataIsZero?: boolean | undefined;
176
151
  complete?: boolean | undefined;
177
152
  error?: string | undefined;
178
153
  } & Record<Exclude<keyof I, keyof CallData>, never>>(object: I): CallData;
@@ -10,11 +10,8 @@ export const Packet = {
10
10
  if (message.body?.$case === 'callStart') {
11
11
  CallStart.encode(message.body.callStart, writer.uint32(10).fork()).ldelim();
12
12
  }
13
- if (message.body?.$case === 'callStartResp') {
14
- CallStartResp.encode(message.body.callStartResp, writer.uint32(18).fork()).ldelim();
15
- }
16
13
  if (message.body?.$case === 'callData') {
17
- CallData.encode(message.body.callData, writer.uint32(26).fork()).ldelim();
14
+ CallData.encode(message.body.callData, writer.uint32(18).fork()).ldelim();
18
15
  }
19
16
  return writer;
20
17
  },
@@ -32,12 +29,6 @@ export const Packet = {
32
29
  };
33
30
  break;
34
31
  case 2:
35
- message.body = {
36
- $case: 'callStartResp',
37
- callStartResp: CallStartResp.decode(reader, reader.uint32()),
38
- };
39
- break;
40
- case 3:
41
32
  message.body = {
42
33
  $case: 'callData',
43
34
  callData: CallData.decode(reader, reader.uint32()),
@@ -57,14 +48,9 @@ export const Packet = {
57
48
  $case: 'callStart',
58
49
  callStart: CallStart.fromJSON(object.callStart),
59
50
  }
60
- : isSet(object.callStartResp)
61
- ? {
62
- $case: 'callStartResp',
63
- callStartResp: CallStartResp.fromJSON(object.callStartResp),
64
- }
65
- : isSet(object.callData)
66
- ? { $case: 'callData', callData: CallData.fromJSON(object.callData) }
67
- : undefined,
51
+ : isSet(object.callData)
52
+ ? { $case: 'callData', callData: CallData.fromJSON(object.callData) }
53
+ : undefined,
68
54
  };
69
55
  },
70
56
  toJSON(message) {
@@ -73,10 +59,6 @@ export const Packet = {
73
59
  (obj.callStart = message.body?.callStart
74
60
  ? CallStart.toJSON(message.body?.callStart)
75
61
  : undefined);
76
- message.body?.$case === 'callStartResp' &&
77
- (obj.callStartResp = message.body?.callStartResp
78
- ? CallStartResp.toJSON(message.body?.callStartResp)
79
- : undefined);
80
62
  message.body?.$case === 'callData' &&
81
63
  (obj.callData = message.body?.callData
82
64
  ? CallData.toJSON(message.body?.callData)
@@ -93,14 +75,6 @@ export const Packet = {
93
75
  callStart: CallStart.fromPartial(object.body.callStart),
94
76
  };
95
77
  }
96
- if (object.body?.$case === 'callStartResp' &&
97
- object.body?.callStartResp !== undefined &&
98
- object.body?.callStartResp !== null) {
99
- message.body = {
100
- $case: 'callStartResp',
101
- callStartResp: CallStartResp.fromPartial(object.body.callStartResp),
102
- };
103
- }
104
78
  if (object.body?.$case === 'callData' &&
105
79
  object.body?.callData !== undefined &&
106
80
  object.body?.callData !== null) {
@@ -113,7 +87,12 @@ export const Packet = {
113
87
  },
114
88
  };
115
89
  function createBaseCallStart() {
116
- return { rpcService: '', rpcMethod: '', data: new Uint8Array() };
90
+ return {
91
+ rpcService: '',
92
+ rpcMethod: '',
93
+ data: new Uint8Array(),
94
+ dataIsZero: false,
95
+ };
117
96
  }
118
97
  export const CallStart = {
119
98
  encode(message, writer = _m0.Writer.create()) {
@@ -126,6 +105,9 @@ export const CallStart = {
126
105
  if (message.data.length !== 0) {
127
106
  writer.uint32(26).bytes(message.data);
128
107
  }
108
+ if (message.dataIsZero === true) {
109
+ writer.uint32(32).bool(message.dataIsZero);
110
+ }
129
111
  return writer;
130
112
  },
131
113
  decode(input, length) {
@@ -144,6 +126,9 @@ export const CallStart = {
144
126
  case 3:
145
127
  message.data = reader.bytes();
146
128
  break;
129
+ case 4:
130
+ message.dataIsZero = reader.bool();
131
+ break;
147
132
  default:
148
133
  reader.skipType(tag & 7);
149
134
  break;
@@ -158,6 +143,7 @@ export const CallStart = {
158
143
  data: isSet(object.data)
159
144
  ? bytesFromBase64(object.data)
160
145
  : new Uint8Array(),
146
+ dataIsZero: isSet(object.dataIsZero) ? Boolean(object.dataIsZero) : false,
161
147
  };
162
148
  },
163
149
  toJSON(message) {
@@ -166,6 +152,7 @@ export const CallStart = {
166
152
  message.rpcMethod !== undefined && (obj.rpcMethod = message.rpcMethod);
167
153
  message.data !== undefined &&
168
154
  (obj.data = base64FromBytes(message.data !== undefined ? message.data : new Uint8Array()));
155
+ message.dataIsZero !== undefined && (obj.dataIsZero = message.dataIsZero);
169
156
  return obj;
170
157
  },
171
158
  fromPartial(object) {
@@ -173,65 +160,31 @@ export const CallStart = {
173
160
  message.rpcService = object.rpcService ?? '';
174
161
  message.rpcMethod = object.rpcMethod ?? '';
175
162
  message.data = object.data ?? new Uint8Array();
176
- return message;
177
- },
178
- };
179
- function createBaseCallStartResp() {
180
- return { error: '' };
181
- }
182
- export const CallStartResp = {
183
- encode(message, writer = _m0.Writer.create()) {
184
- if (message.error !== '') {
185
- writer.uint32(10).string(message.error);
186
- }
187
- return writer;
188
- },
189
- decode(input, length) {
190
- const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
191
- let end = length === undefined ? reader.len : reader.pos + length;
192
- const message = createBaseCallStartResp();
193
- while (reader.pos < end) {
194
- const tag = reader.uint32();
195
- switch (tag >>> 3) {
196
- case 1:
197
- message.error = reader.string();
198
- break;
199
- default:
200
- reader.skipType(tag & 7);
201
- break;
202
- }
203
- }
204
- return message;
205
- },
206
- fromJSON(object) {
207
- return {
208
- error: isSet(object.error) ? String(object.error) : '',
209
- };
210
- },
211
- toJSON(message) {
212
- const obj = {};
213
- message.error !== undefined && (obj.error = message.error);
214
- return obj;
215
- },
216
- fromPartial(object) {
217
- const message = createBaseCallStartResp();
218
- message.error = object.error ?? '';
163
+ message.dataIsZero = object.dataIsZero ?? false;
219
164
  return message;
220
165
  },
221
166
  };
222
167
  function createBaseCallData() {
223
- return { data: new Uint8Array(), complete: false, error: '' };
168
+ return {
169
+ data: new Uint8Array(),
170
+ dataIsZero: false,
171
+ complete: false,
172
+ error: '',
173
+ };
224
174
  }
225
175
  export const CallData = {
226
176
  encode(message, writer = _m0.Writer.create()) {
227
177
  if (message.data.length !== 0) {
228
178
  writer.uint32(10).bytes(message.data);
229
179
  }
180
+ if (message.dataIsZero === true) {
181
+ writer.uint32(16).bool(message.dataIsZero);
182
+ }
230
183
  if (message.complete === true) {
231
- writer.uint32(16).bool(message.complete);
184
+ writer.uint32(24).bool(message.complete);
232
185
  }
233
186
  if (message.error !== '') {
234
- writer.uint32(26).string(message.error);
187
+ writer.uint32(34).string(message.error);
235
188
  }
236
189
  return writer;
237
190
  },
@@ -246,9 +199,12 @@ export const CallData = {
246
199
  message.data = reader.bytes();
247
200
  break;
248
201
  case 2:
249
- message.complete = reader.bool();
202
+ message.dataIsZero = reader.bool();
250
203
  break;
251
204
  case 3:
205
+ message.complete = reader.bool();
206
+ break;
207
+ case 4:
252
208
  message.error = reader.string();
253
209
  break;
254
210
  default:
@@ -263,6 +219,7 @@ export const CallData = {
263
219
  data: isSet(object.data)
264
220
  ? bytesFromBase64(object.data)
265
221
  : new Uint8Array(),
222
+ dataIsZero: isSet(object.dataIsZero) ? Boolean(object.dataIsZero) : false,
266
223
  complete: isSet(object.complete) ? Boolean(object.complete) : false,
267
224
  error: isSet(object.error) ? String(object.error) : '',
268
225
  };
@@ -271,6 +228,7 @@ export const CallData = {
271
228
  const obj = {};
272
229
  message.data !== undefined &&
273
230
  (obj.data = base64FromBytes(message.data !== undefined ? message.data : new Uint8Array()));
231
+ message.dataIsZero !== undefined && (obj.dataIsZero = message.dataIsZero);
274
232
  message.complete !== undefined && (obj.complete = message.complete);
275
233
  message.error !== undefined && (obj.error = message.error);
276
234
  return obj;
@@ -278,6 +236,7 @@ export const CallData = {
278
236
  fromPartial(object) {
279
237
  const message = createBaseCallData();
280
238
  message.data = object.data ?? new Uint8Array();
239
+ message.dataIsZero = object.dataIsZero ?? false;
281
240
  message.complete = object.complete ?? false;
282
241
  message.error = object.error ?? '';
283
242
  return message;
@@ -0,0 +1,11 @@
1
+ import type { CallData, CallStart } from './rpcproto.js';
2
+ import { CommonRPC } from './common-rpc.js';
3
+ import { Mux } from './mux.js';
4
+ export declare class ServerRPC extends CommonRPC {
5
+ private mux;
6
+ constructor(mux: Mux);
7
+ handleCallStart(packet: Partial<CallStart>): Promise<void>;
8
+ handleCallData(packet: Partial<CallData>): Promise<void>;
9
+ private invokeRPC;
10
+ private _createDataSink;
11
+ }
@@ -0,0 +1,55 @@
1
+ import { CommonRPC } from './common-rpc.js';
2
+ // ServerRPC is an ongoing RPC from the server side.
3
+ export class ServerRPC extends CommonRPC {
4
+ // mux is used to handle incoming rpcs.
5
+ mux;
6
+ constructor(mux) {
7
+ super();
8
+ this.mux = mux;
9
+ }
10
+ // handleCallStart handles a CallStart cket.
11
+ async handleCallStart(packet) {
12
+ if (this.service || this.method) {
13
+ throw new Error('call start must be sent only once');
14
+ }
15
+ this.service = packet.rpcService;
16
+ this.method = packet.rpcMethod;
17
+ if (!this.service || !this.method) {
18
+ throw new Error('rpcService and rpcMethod cannot be empty');
19
+ }
20
+ const methodDef = await this.mux.lookupMethod(this.service, this.method);
21
+ if (!methodDef) {
22
+ throw new Error(`not found: ${this.service}/${this.method}`);
23
+ }
24
+ this.pushRpcData(packet.data, packet.dataIsZero);
25
+ this.invokeRPC(methodDef);
26
+ }
27
+ // handleCallData handles a CallData packet.
28
+ async handleCallData(packet) {
29
+ if (!this.service || !this.method) {
30
+ throw new Error('call start must be sent before call data');
31
+ }
32
+ return super.handleCallData(packet);
33
+ }
34
+ // invokeRPC starts invoking the RPC handler.
35
+ invokeRPC(invokeFn) {
36
+ const dataSink = this._createDataSink();
37
+ invokeFn(this.rpcDataSource, dataSink).catch((err) => {
38
+ this.close(err);
39
+ });
40
+ }
41
+ // _createDataSink creates a sink for outgoing data packets.
42
+ _createDataSink() {
43
+ return async (source) => {
44
+ try {
45
+ for await (const msg of source) {
46
+ await this.writeCallData(msg);
47
+ }
48
+ await this.writeCallData(undefined, true);
49
+ }
50
+ catch (err) {
51
+ this.close(err);
52
+ }
53
+ };
54
+ }
55
+ }
@@ -0,0 +1,14 @@
1
+ import { Stream } from '@libp2p/interface-connection';
2
+ import { Duplex } from 'it-stream-types';
3
+ import { Mux } from './mux.js';
4
+ import { ServerRPC } from './server-rpc.js';
5
+ import { Packet } from './rpcproto.js';
6
+ import { StreamHandler } from './conn.js';
7
+ export declare class Server implements StreamHandler {
8
+ private mux;
9
+ constructor(mux: Mux);
10
+ startRpc(): ServerRPC;
11
+ handleStream(stream: Stream): Promise<void>;
12
+ handleDuplex(stream: Duplex<Uint8Array>): Promise<void>;
13
+ handlePacketStream(stream: Duplex<Packet>): Promise<void>;
14
+ }
@@ -0,0 +1,31 @@
1
+ import { pipe } from 'it-pipe';
2
+ import { ServerRPC } from './server-rpc.js';
3
+ import { parseLengthPrefixTransform, prependLengthPrefixTransform, decodePacketSource, encodePacketSource, } from './packet.js';
4
+ // Server implements the SRPC server in TypeScript with a Mux.
5
+ export class Server {
6
+ // mux is the mux used to handle requests.
7
+ mux;
8
+ constructor(mux) {
9
+ this.mux = mux;
10
+ }
11
+ // startRpc starts a new server-side RPC.
12
+ // the returned RPC handles incoming Packets.
13
+ startRpc() {
14
+ return new ServerRPC(this.mux);
15
+ }
16
+ // handleStream handles an incoming Uint8Array message duplex.
17
+ // closes the stream when the rpc completes.
18
+ handleStream(stream) {
19
+ return this.handleDuplex(stream);
20
+ }
21
+ // handleDuplex handles an incoming message duplex.
22
+ async handleDuplex(stream) {
23
+ const rpc = this.startRpc();
24
+ await pipe(stream, parseLengthPrefixTransform(), decodePacketSource, rpc, encodePacketSource, prependLengthPrefixTransform(), stream);
25
+ }
26
+ // handlePacketStream handles an incoming Packet duplex.
27
+ async handlePacketStream(stream) {
28
+ const rpc = this.startRpc();
29
+ await pipe(stream, rpc, stream);
30
+ }
31
+ }
@@ -1,7 +1,8 @@
1
- import { Conn } from './conn.js';
2
1
  import type WebSocket from 'isomorphic-ws';
2
+ import { Conn } from './conn.js';
3
+ import { Server } from './server.js';
3
4
  export declare class WebSocketConn extends Conn {
4
5
  private socket;
5
- constructor(socket: WebSocket);
6
+ constructor(socket: WebSocket, server?: Server);
6
7
  getSocket(): WebSocket;
7
8
  }
@@ -1,13 +1,13 @@
1
- import { Conn } from './conn.js';
2
1
  import { duplex } from 'it-ws';
3
2
  import { pipe } from 'it-pipe';
4
3
  import { Mplex } from '@libp2p/mplex';
5
- // WebSocketConn implements a connection with a WebSocket.
4
+ import { Conn } from './conn.js';
5
+ // WebSocketConn implements a connection with a WebSocket and optional Server.
6
6
  export class WebSocketConn extends Conn {
7
7
  // socket is the web socket
8
8
  socket;
9
- constructor(socket) {
10
- super({
9
+ constructor(socket, server) {
10
+ super(server, {
11
11
  muxerFactory: new Mplex(),
12
12
  });
13
13
  this.socket = socket;
package/e2e/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # E2E
2
+
3
+ E2E contains tests using the client and server written in the same language.
4
+
5
+ For example:
6
+
7
+ - Go Client calling Go server: "go test" or "yarn test:go"
8
+ - TypeScript client calling TypeScript server: "yarn test:js"
9
+
10
+ For cross-language tests, i.e. Ts <-> Go, see [integration](../integration).