starpc 0.0.1 → 0.1.2
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.
- package/LICENSE +19 -0
- package/Makefile +140 -0
- package/README.md +128 -26
- package/dist/echo/echo.d.ts +59 -0
- package/dist/echo/echo.js +85 -0
- package/dist/srpc/broadcast-channel.d.ts +16 -0
- package/dist/srpc/broadcast-channel.js +60 -0
- package/dist/srpc/client-rpc.d.ts +31 -0
- package/dist/srpc/client-rpc.js +176 -0
- package/dist/srpc/client.d.ts +12 -0
- package/dist/srpc/client.js +129 -0
- package/dist/srpc/conn.d.ts +14 -0
- package/dist/srpc/conn.js +38 -0
- package/dist/srpc/index.d.ts +3 -0
- package/dist/srpc/index.js +2 -0
- package/dist/srpc/packet.d.ts +9 -0
- package/dist/srpc/packet.js +89 -0
- package/dist/srpc/rpcproto.d.ts +194 -0
- package/dist/srpc/rpcproto.js +322 -0
- package/dist/srpc/stream.d.ts +5 -0
- package/dist/srpc/stream.js +1 -0
- package/dist/srpc/ts-proto-rpc.d.ts +7 -0
- package/dist/srpc/ts-proto-rpc.js +1 -0
- package/dist/srpc/websocket.d.ts +7 -0
- package/dist/srpc/websocket.js +18 -0
- package/e2e/e2e.go +1 -0
- package/e2e/e2e_test.go +158 -0
- package/echo/echo.go +1 -0
- package/echo/echo.pb.go +165 -0
- package/echo/echo.proto +19 -0
- package/echo/echo.ts +191 -0
- package/echo/echo_srpc.pb.go +333 -0
- package/echo/echo_vtproto.pb.go +271 -0
- package/echo/server.go +73 -0
- package/go.mod +50 -0
- package/go.sum +210 -0
- package/integration/integration.bash +25 -0
- package/integration/integration.go +30 -0
- package/integration/integration.ts +54 -0
- package/integration/tsconfig.json +11 -0
- package/package.json +77 -9
- package/patches/@libp2p+mplex+1.2.1.patch +22 -0
- package/srpc/broadcast-channel.ts +72 -0
- package/srpc/client-rpc.go +163 -0
- package/srpc/client-rpc.ts +197 -0
- package/srpc/client.go +96 -0
- package/srpc/client.ts +182 -0
- package/srpc/conn.go +7 -0
- package/srpc/conn.ts +49 -0
- package/srpc/errors.go +20 -0
- package/srpc/handler.go +13 -0
- package/srpc/index.ts +3 -0
- package/srpc/message.go +7 -0
- package/srpc/mux.go +76 -0
- package/srpc/packet-rw.go +102 -0
- package/srpc/packet.go +71 -0
- package/srpc/packet.ts +105 -0
- package/srpc/rpc-stream.go +76 -0
- package/srpc/rpcproto.pb.go +455 -0
- package/srpc/rpcproto.proto +46 -0
- package/srpc/rpcproto.ts +467 -0
- package/srpc/rpcproto_vtproto.pb.go +1094 -0
- package/srpc/server-http.go +66 -0
- package/srpc/server-pipe.go +26 -0
- package/srpc/server-rpc.go +160 -0
- package/srpc/server.go +29 -0
- package/srpc/stream-pipe.go +86 -0
- package/srpc/stream.go +24 -0
- package/srpc/stream.ts +11 -0
- package/srpc/ts-proto-rpc.ts +29 -0
- package/srpc/websocket.go +68 -0
- package/srpc/websocket.ts +22 -0
- package/srpc/writer.go +9 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import Long from 'long';
|
|
3
|
+
import * as _m0 from 'protobufjs/minimal';
|
|
4
|
+
export const protobufPackage = 'srpc';
|
|
5
|
+
function createBasePacket() {
|
|
6
|
+
return { body: undefined };
|
|
7
|
+
}
|
|
8
|
+
export const Packet = {
|
|
9
|
+
encode(message, writer = _m0.Writer.create()) {
|
|
10
|
+
if (message.body?.$case === 'callStart') {
|
|
11
|
+
CallStart.encode(message.body.callStart, writer.uint32(10).fork()).ldelim();
|
|
12
|
+
}
|
|
13
|
+
if (message.body?.$case === 'callStartResp') {
|
|
14
|
+
CallStartResp.encode(message.body.callStartResp, writer.uint32(18).fork()).ldelim();
|
|
15
|
+
}
|
|
16
|
+
if (message.body?.$case === 'callData') {
|
|
17
|
+
CallData.encode(message.body.callData, writer.uint32(26).fork()).ldelim();
|
|
18
|
+
}
|
|
19
|
+
return writer;
|
|
20
|
+
},
|
|
21
|
+
decode(input, length) {
|
|
22
|
+
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
|
23
|
+
let end = length === undefined ? reader.len : reader.pos + length;
|
|
24
|
+
const message = createBasePacket();
|
|
25
|
+
while (reader.pos < end) {
|
|
26
|
+
const tag = reader.uint32();
|
|
27
|
+
switch (tag >>> 3) {
|
|
28
|
+
case 1:
|
|
29
|
+
message.body = {
|
|
30
|
+
$case: 'callStart',
|
|
31
|
+
callStart: CallStart.decode(reader, reader.uint32()),
|
|
32
|
+
};
|
|
33
|
+
break;
|
|
34
|
+
case 2:
|
|
35
|
+
message.body = {
|
|
36
|
+
$case: 'callStartResp',
|
|
37
|
+
callStartResp: CallStartResp.decode(reader, reader.uint32()),
|
|
38
|
+
};
|
|
39
|
+
break;
|
|
40
|
+
case 3:
|
|
41
|
+
message.body = {
|
|
42
|
+
$case: 'callData',
|
|
43
|
+
callData: CallData.decode(reader, reader.uint32()),
|
|
44
|
+
};
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
reader.skipType(tag & 7);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return message;
|
|
52
|
+
},
|
|
53
|
+
fromJSON(object) {
|
|
54
|
+
return {
|
|
55
|
+
body: isSet(object.callStart)
|
|
56
|
+
? {
|
|
57
|
+
$case: 'callStart',
|
|
58
|
+
callStart: CallStart.fromJSON(object.callStart),
|
|
59
|
+
}
|
|
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,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
toJSON(message) {
|
|
71
|
+
const obj = {};
|
|
72
|
+
message.body?.$case === 'callStart' &&
|
|
73
|
+
(obj.callStart = message.body?.callStart
|
|
74
|
+
? CallStart.toJSON(message.body?.callStart)
|
|
75
|
+
: undefined);
|
|
76
|
+
message.body?.$case === 'callStartResp' &&
|
|
77
|
+
(obj.callStartResp = message.body?.callStartResp
|
|
78
|
+
? CallStartResp.toJSON(message.body?.callStartResp)
|
|
79
|
+
: undefined);
|
|
80
|
+
message.body?.$case === 'callData' &&
|
|
81
|
+
(obj.callData = message.body?.callData
|
|
82
|
+
? CallData.toJSON(message.body?.callData)
|
|
83
|
+
: undefined);
|
|
84
|
+
return obj;
|
|
85
|
+
},
|
|
86
|
+
fromPartial(object) {
|
|
87
|
+
const message = createBasePacket();
|
|
88
|
+
if (object.body?.$case === 'callStart' &&
|
|
89
|
+
object.body?.callStart !== undefined &&
|
|
90
|
+
object.body?.callStart !== null) {
|
|
91
|
+
message.body = {
|
|
92
|
+
$case: 'callStart',
|
|
93
|
+
callStart: CallStart.fromPartial(object.body.callStart),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
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
|
+
if (object.body?.$case === 'callData' &&
|
|
105
|
+
object.body?.callData !== undefined &&
|
|
106
|
+
object.body?.callData !== null) {
|
|
107
|
+
message.body = {
|
|
108
|
+
$case: 'callData',
|
|
109
|
+
callData: CallData.fromPartial(object.body.callData),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return message;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
function createBaseCallStart() {
|
|
116
|
+
return { rpcService: '', rpcMethod: '', data: new Uint8Array() };
|
|
117
|
+
}
|
|
118
|
+
export const CallStart = {
|
|
119
|
+
encode(message, writer = _m0.Writer.create()) {
|
|
120
|
+
if (message.rpcService !== '') {
|
|
121
|
+
writer.uint32(10).string(message.rpcService);
|
|
122
|
+
}
|
|
123
|
+
if (message.rpcMethod !== '') {
|
|
124
|
+
writer.uint32(18).string(message.rpcMethod);
|
|
125
|
+
}
|
|
126
|
+
if (message.data.length !== 0) {
|
|
127
|
+
writer.uint32(26).bytes(message.data);
|
|
128
|
+
}
|
|
129
|
+
return writer;
|
|
130
|
+
},
|
|
131
|
+
decode(input, length) {
|
|
132
|
+
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
|
133
|
+
let end = length === undefined ? reader.len : reader.pos + length;
|
|
134
|
+
const message = createBaseCallStart();
|
|
135
|
+
while (reader.pos < end) {
|
|
136
|
+
const tag = reader.uint32();
|
|
137
|
+
switch (tag >>> 3) {
|
|
138
|
+
case 1:
|
|
139
|
+
message.rpcService = reader.string();
|
|
140
|
+
break;
|
|
141
|
+
case 2:
|
|
142
|
+
message.rpcMethod = reader.string();
|
|
143
|
+
break;
|
|
144
|
+
case 3:
|
|
145
|
+
message.data = reader.bytes();
|
|
146
|
+
break;
|
|
147
|
+
default:
|
|
148
|
+
reader.skipType(tag & 7);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return message;
|
|
153
|
+
},
|
|
154
|
+
fromJSON(object) {
|
|
155
|
+
return {
|
|
156
|
+
rpcService: isSet(object.rpcService) ? String(object.rpcService) : '',
|
|
157
|
+
rpcMethod: isSet(object.rpcMethod) ? String(object.rpcMethod) : '',
|
|
158
|
+
data: isSet(object.data)
|
|
159
|
+
? bytesFromBase64(object.data)
|
|
160
|
+
: new Uint8Array(),
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
toJSON(message) {
|
|
164
|
+
const obj = {};
|
|
165
|
+
message.rpcService !== undefined && (obj.rpcService = message.rpcService);
|
|
166
|
+
message.rpcMethod !== undefined && (obj.rpcMethod = message.rpcMethod);
|
|
167
|
+
message.data !== undefined &&
|
|
168
|
+
(obj.data = base64FromBytes(message.data !== undefined ? message.data : new Uint8Array()));
|
|
169
|
+
return obj;
|
|
170
|
+
},
|
|
171
|
+
fromPartial(object) {
|
|
172
|
+
const message = createBaseCallStart();
|
|
173
|
+
message.rpcService = object.rpcService ?? '';
|
|
174
|
+
message.rpcMethod = object.rpcMethod ?? '';
|
|
175
|
+
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 ?? '';
|
|
219
|
+
return message;
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
function createBaseCallData() {
|
|
223
|
+
return { data: new Uint8Array(), complete: false, error: '' };
|
|
224
|
+
}
|
|
225
|
+
export const CallData = {
|
|
226
|
+
encode(message, writer = _m0.Writer.create()) {
|
|
227
|
+
if (message.data.length !== 0) {
|
|
228
|
+
writer.uint32(10).bytes(message.data);
|
|
229
|
+
}
|
|
230
|
+
if (message.complete === true) {
|
|
231
|
+
writer.uint32(16).bool(message.complete);
|
|
232
|
+
}
|
|
233
|
+
if (message.error !== '') {
|
|
234
|
+
writer.uint32(26).string(message.error);
|
|
235
|
+
}
|
|
236
|
+
return writer;
|
|
237
|
+
},
|
|
238
|
+
decode(input, length) {
|
|
239
|
+
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
|
240
|
+
let end = length === undefined ? reader.len : reader.pos + length;
|
|
241
|
+
const message = createBaseCallData();
|
|
242
|
+
while (reader.pos < end) {
|
|
243
|
+
const tag = reader.uint32();
|
|
244
|
+
switch (tag >>> 3) {
|
|
245
|
+
case 1:
|
|
246
|
+
message.data = reader.bytes();
|
|
247
|
+
break;
|
|
248
|
+
case 2:
|
|
249
|
+
message.complete = reader.bool();
|
|
250
|
+
break;
|
|
251
|
+
case 3:
|
|
252
|
+
message.error = reader.string();
|
|
253
|
+
break;
|
|
254
|
+
default:
|
|
255
|
+
reader.skipType(tag & 7);
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return message;
|
|
260
|
+
},
|
|
261
|
+
fromJSON(object) {
|
|
262
|
+
return {
|
|
263
|
+
data: isSet(object.data)
|
|
264
|
+
? bytesFromBase64(object.data)
|
|
265
|
+
: new Uint8Array(),
|
|
266
|
+
complete: isSet(object.complete) ? Boolean(object.complete) : false,
|
|
267
|
+
error: isSet(object.error) ? String(object.error) : '',
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
toJSON(message) {
|
|
271
|
+
const obj = {};
|
|
272
|
+
message.data !== undefined &&
|
|
273
|
+
(obj.data = base64FromBytes(message.data !== undefined ? message.data : new Uint8Array()));
|
|
274
|
+
message.complete !== undefined && (obj.complete = message.complete);
|
|
275
|
+
message.error !== undefined && (obj.error = message.error);
|
|
276
|
+
return obj;
|
|
277
|
+
},
|
|
278
|
+
fromPartial(object) {
|
|
279
|
+
const message = createBaseCallData();
|
|
280
|
+
message.data = object.data ?? new Uint8Array();
|
|
281
|
+
message.complete = object.complete ?? false;
|
|
282
|
+
message.error = object.error ?? '';
|
|
283
|
+
return message;
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
var globalThis = (() => {
|
|
287
|
+
if (typeof globalThis !== 'undefined')
|
|
288
|
+
return globalThis;
|
|
289
|
+
if (typeof self !== 'undefined')
|
|
290
|
+
return self;
|
|
291
|
+
if (typeof window !== 'undefined')
|
|
292
|
+
return window;
|
|
293
|
+
if (typeof global !== 'undefined')
|
|
294
|
+
return global;
|
|
295
|
+
throw 'Unable to locate global object';
|
|
296
|
+
})();
|
|
297
|
+
const atob = globalThis.atob ||
|
|
298
|
+
((b64) => globalThis.Buffer.from(b64, 'base64').toString('binary'));
|
|
299
|
+
function bytesFromBase64(b64) {
|
|
300
|
+
const bin = atob(b64);
|
|
301
|
+
const arr = new Uint8Array(bin.length);
|
|
302
|
+
for (let i = 0; i < bin.length; ++i) {
|
|
303
|
+
arr[i] = bin.charCodeAt(i);
|
|
304
|
+
}
|
|
305
|
+
return arr;
|
|
306
|
+
}
|
|
307
|
+
const btoa = globalThis.btoa ||
|
|
308
|
+
((bin) => globalThis.Buffer.from(bin, 'binary').toString('base64'));
|
|
309
|
+
function base64FromBytes(arr) {
|
|
310
|
+
const bin = [];
|
|
311
|
+
arr.forEach((byte) => {
|
|
312
|
+
bin.push(String.fromCharCode(byte));
|
|
313
|
+
});
|
|
314
|
+
return btoa(bin.join(''));
|
|
315
|
+
}
|
|
316
|
+
if (_m0.util.Long !== Long) {
|
|
317
|
+
_m0.util.Long = Long;
|
|
318
|
+
_m0.configure();
|
|
319
|
+
}
|
|
320
|
+
function isSet(value) {
|
|
321
|
+
return value !== null && value !== undefined;
|
|
322
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Packet } from './rpcproto';
|
|
2
|
+
import type { Duplex } from 'it-stream-types';
|
|
3
|
+
export declare type PacketHandler = (packet: Packet) => Promise<void>;
|
|
4
|
+
export declare type Stream = Duplex<Uint8Array>;
|
|
5
|
+
export declare type OpenStreamFunc = () => Promise<Stream>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
export interface TsProtoRpc {
|
|
3
|
+
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>;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Conn } from './conn.js';
|
|
2
|
+
import { duplex } from 'it-ws';
|
|
3
|
+
import { pipe } from 'it-pipe';
|
|
4
|
+
// WebSocketConn implements a connection with a WebSocket.
|
|
5
|
+
export class WebSocketConn extends Conn {
|
|
6
|
+
// socket is the web socket
|
|
7
|
+
socket;
|
|
8
|
+
constructor(socket) {
|
|
9
|
+
super();
|
|
10
|
+
this.socket = socket;
|
|
11
|
+
const socketDuplex = duplex(socket);
|
|
12
|
+
pipe(this.source, socketDuplex, this.sink);
|
|
13
|
+
}
|
|
14
|
+
// getSocket returns the websocket.
|
|
15
|
+
getSocket() {
|
|
16
|
+
return this.socket;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/e2e/e2e.go
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
package e2e
|
package/e2e/e2e_test.go
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
package e2e
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"io"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
"github.com/aperturerobotics/starpc/echo"
|
|
9
|
+
"github.com/aperturerobotics/starpc/srpc"
|
|
10
|
+
"github.com/pkg/errors"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// RunE2E runs an end to end test with a callback.
|
|
14
|
+
func RunE2E(t *testing.T, cb func(client echo.SRPCEchoerClient) error) {
|
|
15
|
+
// construct the server
|
|
16
|
+
echoServer := &echo.EchoServer{}
|
|
17
|
+
mux := srpc.NewMux()
|
|
18
|
+
if err := echo.SRPCRegisterEchoer(mux, echoServer); err != nil {
|
|
19
|
+
t.Fatal(err.Error())
|
|
20
|
+
}
|
|
21
|
+
server := srpc.NewServer(mux)
|
|
22
|
+
|
|
23
|
+
// construct the client
|
|
24
|
+
openStream := srpc.NewServerPipe(server)
|
|
25
|
+
client := srpc.NewClient(openStream)
|
|
26
|
+
|
|
27
|
+
// construct the client rpc interface
|
|
28
|
+
clientEcho := echo.NewSRPCEchoerClient(client)
|
|
29
|
+
|
|
30
|
+
// call
|
|
31
|
+
if err := cb(clientEcho); err != nil {
|
|
32
|
+
t.Fatal(err.Error())
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func TestE2E_Unary(t *testing.T) {
|
|
37
|
+
ctx := context.Background()
|
|
38
|
+
RunE2E(t, func(client echo.SRPCEchoerClient) error {
|
|
39
|
+
bodyTxt := "hello world"
|
|
40
|
+
out, err := client.Echo(ctx, &echo.EchoMsg{
|
|
41
|
+
Body: bodyTxt,
|
|
42
|
+
})
|
|
43
|
+
if err != nil {
|
|
44
|
+
t.Fatal(err.Error())
|
|
45
|
+
}
|
|
46
|
+
if out.GetBody() != bodyTxt {
|
|
47
|
+
t.Fatalf("expected %q got %q", bodyTxt, out.GetBody())
|
|
48
|
+
}
|
|
49
|
+
return nil
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// CheckServerStream checks the server stream portion of the Echo test.
|
|
54
|
+
func CheckServerStream(t *testing.T, out echo.SRPCEchoer_EchoServerStreamClient, req *echo.EchoMsg) error {
|
|
55
|
+
// expect to rx 5, then close
|
|
56
|
+
expectedRx := 5
|
|
57
|
+
totalExpected := expectedRx
|
|
58
|
+
for {
|
|
59
|
+
echoMsg, err := out.Recv()
|
|
60
|
+
if err != nil {
|
|
61
|
+
if err == io.EOF {
|
|
62
|
+
break
|
|
63
|
+
}
|
|
64
|
+
return err
|
|
65
|
+
}
|
|
66
|
+
body := echoMsg.GetBody()
|
|
67
|
+
bodyTxt := req.GetBody()
|
|
68
|
+
if body != bodyTxt {
|
|
69
|
+
return errors.Errorf("expected %q got %q", bodyTxt, body)
|
|
70
|
+
}
|
|
71
|
+
t.Logf("server->client message %d/%d", totalExpected-expectedRx+1, totalExpected)
|
|
72
|
+
expectedRx--
|
|
73
|
+
}
|
|
74
|
+
if expectedRx < 0 {
|
|
75
|
+
return errors.Errorf("got %d more messages than expected", -1*expectedRx)
|
|
76
|
+
}
|
|
77
|
+
return nil
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func TestE2E_ServerStream(t *testing.T) {
|
|
81
|
+
ctx := context.Background()
|
|
82
|
+
RunE2E(t, func(client echo.SRPCEchoerClient) error {
|
|
83
|
+
bodyTxt := "hello world"
|
|
84
|
+
req := &echo.EchoMsg{
|
|
85
|
+
Body: bodyTxt,
|
|
86
|
+
}
|
|
87
|
+
out, err := client.EchoServerStream(ctx, req)
|
|
88
|
+
if err != nil {
|
|
89
|
+
t.Fatal(err.Error())
|
|
90
|
+
}
|
|
91
|
+
return CheckServerStream(t, out, req)
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// CheckClientStream checks the server stream portion of the Echo test.
|
|
96
|
+
func CheckClientStream(t *testing.T, out echo.SRPCEchoer_EchoClientStreamClient, req *echo.EchoMsg) error {
|
|
97
|
+
// send request
|
|
98
|
+
if err := out.MsgSend(req); err != nil {
|
|
99
|
+
return err
|
|
100
|
+
}
|
|
101
|
+
// expect 1 response
|
|
102
|
+
ret := &echo.EchoMsg{}
|
|
103
|
+
if err := out.MsgRecv(ret); err != nil {
|
|
104
|
+
return err
|
|
105
|
+
}
|
|
106
|
+
// check response
|
|
107
|
+
if ret.GetBody() != req.GetBody() {
|
|
108
|
+
return errors.Errorf("expected %q got %q", req.GetBody(), ret.GetBody())
|
|
109
|
+
}
|
|
110
|
+
_ = out.Close()
|
|
111
|
+
return nil
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
func TestE2E_ClientStream(t *testing.T) {
|
|
115
|
+
ctx := context.Background()
|
|
116
|
+
RunE2E(t, func(client echo.SRPCEchoerClient) error {
|
|
117
|
+
bodyTxt := "hello world"
|
|
118
|
+
req := &echo.EchoMsg{
|
|
119
|
+
Body: bodyTxt,
|
|
120
|
+
}
|
|
121
|
+
out, err := client.EchoClientStream(ctx)
|
|
122
|
+
if err != nil {
|
|
123
|
+
t.Fatal(err.Error())
|
|
124
|
+
}
|
|
125
|
+
return CheckClientStream(t, out, req)
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func TestE2E_BidiStream(t *testing.T) {
|
|
130
|
+
ctx := context.Background()
|
|
131
|
+
RunE2E(t, func(client echo.SRPCEchoerClient) error {
|
|
132
|
+
strm, err := client.EchoBidiStream(ctx)
|
|
133
|
+
if err != nil {
|
|
134
|
+
t.Fatal(err.Error())
|
|
135
|
+
}
|
|
136
|
+
clientExpected := "hello from client"
|
|
137
|
+
if err := strm.MsgSend(&echo.EchoMsg{Body: clientExpected}); err != nil {
|
|
138
|
+
t.Fatal(err.Error())
|
|
139
|
+
}
|
|
140
|
+
msg, err := strm.Recv()
|
|
141
|
+
if err != nil {
|
|
142
|
+
t.Fatal(err.Error())
|
|
143
|
+
}
|
|
144
|
+
expected := "hello from server"
|
|
145
|
+
if msg.GetBody() != expected {
|
|
146
|
+
t.Fatalf("expected %q got %q", expected, msg.GetBody())
|
|
147
|
+
}
|
|
148
|
+
msg, err = strm.Recv()
|
|
149
|
+
if err != nil {
|
|
150
|
+
t.Fatal(err.Error())
|
|
151
|
+
}
|
|
152
|
+
if msg.GetBody() != clientExpected {
|
|
153
|
+
t.Fatalf("expected %q got %q", clientExpected, msg.GetBody())
|
|
154
|
+
}
|
|
155
|
+
// expect no error closing
|
|
156
|
+
return strm.Close()
|
|
157
|
+
})
|
|
158
|
+
}
|
package/echo/echo.go
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
package echo
|
package/echo/echo.pb.go
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
2
|
+
// versions:
|
|
3
|
+
// protoc-gen-go v1.27.1-devel
|
|
4
|
+
// protoc v3.19.3
|
|
5
|
+
// source: github.com/aperturerobotics/starpc/echo/echo.proto
|
|
6
|
+
|
|
7
|
+
package echo
|
|
8
|
+
|
|
9
|
+
import (
|
|
10
|
+
reflect "reflect"
|
|
11
|
+
sync "sync"
|
|
12
|
+
|
|
13
|
+
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
14
|
+
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const (
|
|
18
|
+
// Verify that this generated code is sufficiently up-to-date.
|
|
19
|
+
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
20
|
+
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
21
|
+
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// EchoMsg is the message body for Echo.
|
|
25
|
+
type EchoMsg struct {
|
|
26
|
+
state protoimpl.MessageState
|
|
27
|
+
sizeCache protoimpl.SizeCache
|
|
28
|
+
unknownFields protoimpl.UnknownFields
|
|
29
|
+
|
|
30
|
+
Body string `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func (x *EchoMsg) Reset() {
|
|
34
|
+
*x = EchoMsg{}
|
|
35
|
+
if protoimpl.UnsafeEnabled {
|
|
36
|
+
mi := &file_github_com_aperturerobotics_starpc_echo_echo_proto_msgTypes[0]
|
|
37
|
+
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
38
|
+
ms.StoreMessageInfo(mi)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func (x *EchoMsg) String() string {
|
|
43
|
+
return protoimpl.X.MessageStringOf(x)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func (*EchoMsg) ProtoMessage() {}
|
|
47
|
+
|
|
48
|
+
func (x *EchoMsg) ProtoReflect() protoreflect.Message {
|
|
49
|
+
mi := &file_github_com_aperturerobotics_starpc_echo_echo_proto_msgTypes[0]
|
|
50
|
+
if protoimpl.UnsafeEnabled && x != nil {
|
|
51
|
+
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
52
|
+
if ms.LoadMessageInfo() == nil {
|
|
53
|
+
ms.StoreMessageInfo(mi)
|
|
54
|
+
}
|
|
55
|
+
return ms
|
|
56
|
+
}
|
|
57
|
+
return mi.MessageOf(x)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Deprecated: Use EchoMsg.ProtoReflect.Descriptor instead.
|
|
61
|
+
func (*EchoMsg) Descriptor() ([]byte, []int) {
|
|
62
|
+
return file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescGZIP(), []int{0}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func (x *EchoMsg) GetBody() string {
|
|
66
|
+
if x != nil {
|
|
67
|
+
return x.Body
|
|
68
|
+
}
|
|
69
|
+
return ""
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
var File_github_com_aperturerobotics_starpc_echo_echo_proto protoreflect.FileDescriptor
|
|
73
|
+
|
|
74
|
+
var file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDesc = []byte{
|
|
75
|
+
0x0a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x65,
|
|
76
|
+
0x72, 0x74, 0x75, 0x72, 0x65, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x69, 0x63, 0x73, 0x2f, 0x73, 0x74,
|
|
77
|
+
0x61, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x70,
|
|
78
|
+
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x65, 0x63, 0x68, 0x6f, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x63,
|
|
79
|
+
0x68, 0x6f, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20,
|
|
80
|
+
0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x32, 0xca, 0x01, 0x0a, 0x06, 0x45, 0x63,
|
|
81
|
+
0x68, 0x6f, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x0d, 0x2e, 0x65,
|
|
82
|
+
0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63,
|
|
83
|
+
0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x12, 0x32, 0x0a, 0x10, 0x45, 0x63,
|
|
84
|
+
0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x0d,
|
|
85
|
+
0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e,
|
|
86
|
+
0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x30, 0x01, 0x12, 0x32,
|
|
87
|
+
0x0a, 0x10, 0x45, 0x63, 0x68, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65,
|
|
88
|
+
0x61, 0x6d, 0x12, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73,
|
|
89
|
+
0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67,
|
|
90
|
+
0x28, 0x01, 0x12, 0x32, 0x0a, 0x0e, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74,
|
|
91
|
+
0x72, 0x65, 0x61, 0x6d, 0x12, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f,
|
|
92
|
+
0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d,
|
|
93
|
+
0x73, 0x67, 0x28, 0x01, 0x30, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
var (
|
|
97
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescOnce sync.Once
|
|
98
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescData = file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDesc
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
func file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescGZIP() []byte {
|
|
102
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescOnce.Do(func() {
|
|
103
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescData)
|
|
104
|
+
})
|
|
105
|
+
return file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescData
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var file_github_com_aperturerobotics_starpc_echo_echo_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
109
|
+
var file_github_com_aperturerobotics_starpc_echo_echo_proto_goTypes = []interface{}{
|
|
110
|
+
(*EchoMsg)(nil), // 0: echo.EchoMsg
|
|
111
|
+
}
|
|
112
|
+
var file_github_com_aperturerobotics_starpc_echo_echo_proto_depIdxs = []int32{
|
|
113
|
+
0, // 0: echo.Echoer.Echo:input_type -> echo.EchoMsg
|
|
114
|
+
0, // 1: echo.Echoer.EchoServerStream:input_type -> echo.EchoMsg
|
|
115
|
+
0, // 2: echo.Echoer.EchoClientStream:input_type -> echo.EchoMsg
|
|
116
|
+
0, // 3: echo.Echoer.EchoBidiStream:input_type -> echo.EchoMsg
|
|
117
|
+
0, // 4: echo.Echoer.Echo:output_type -> echo.EchoMsg
|
|
118
|
+
0, // 5: echo.Echoer.EchoServerStream:output_type -> echo.EchoMsg
|
|
119
|
+
0, // 6: echo.Echoer.EchoClientStream:output_type -> echo.EchoMsg
|
|
120
|
+
0, // 7: echo.Echoer.EchoBidiStream:output_type -> echo.EchoMsg
|
|
121
|
+
4, // [4:8] is the sub-list for method output_type
|
|
122
|
+
0, // [0:4] is the sub-list for method input_type
|
|
123
|
+
0, // [0:0] is the sub-list for extension type_name
|
|
124
|
+
0, // [0:0] is the sub-list for extension extendee
|
|
125
|
+
0, // [0:0] is the sub-list for field type_name
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func init() { file_github_com_aperturerobotics_starpc_echo_echo_proto_init() }
|
|
129
|
+
func file_github_com_aperturerobotics_starpc_echo_echo_proto_init() {
|
|
130
|
+
if File_github_com_aperturerobotics_starpc_echo_echo_proto != nil {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
if !protoimpl.UnsafeEnabled {
|
|
134
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
135
|
+
switch v := v.(*EchoMsg); i {
|
|
136
|
+
case 0:
|
|
137
|
+
return &v.state
|
|
138
|
+
case 1:
|
|
139
|
+
return &v.sizeCache
|
|
140
|
+
case 2:
|
|
141
|
+
return &v.unknownFields
|
|
142
|
+
default:
|
|
143
|
+
return nil
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
type x struct{}
|
|
148
|
+
out := protoimpl.TypeBuilder{
|
|
149
|
+
File: protoimpl.DescBuilder{
|
|
150
|
+
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
151
|
+
RawDescriptor: file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDesc,
|
|
152
|
+
NumEnums: 0,
|
|
153
|
+
NumMessages: 1,
|
|
154
|
+
NumExtensions: 0,
|
|
155
|
+
NumServices: 1,
|
|
156
|
+
},
|
|
157
|
+
GoTypes: file_github_com_aperturerobotics_starpc_echo_echo_proto_goTypes,
|
|
158
|
+
DependencyIndexes: file_github_com_aperturerobotics_starpc_echo_echo_proto_depIdxs,
|
|
159
|
+
MessageInfos: file_github_com_aperturerobotics_starpc_echo_echo_proto_msgTypes,
|
|
160
|
+
}.Build()
|
|
161
|
+
File_github_com_aperturerobotics_starpc_echo_echo_proto = out.File
|
|
162
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDesc = nil
|
|
163
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_goTypes = nil
|
|
164
|
+
file_github_com_aperturerobotics_starpc_echo_echo_proto_depIdxs = nil
|
|
165
|
+
}
|