starpc 0.25.3 → 0.25.5
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/dist/e2e/e2e.js +6 -2
- package/dist/echo/client-test.js +36 -16
- package/dist/srpc/client.js +9 -10
- package/dist/srpc/common-rpc.d.ts +1 -1
- package/dist/srpc/common-rpc.js +7 -9
- package/dist/srpc/pushable.js +2 -1
- package/e2e/e2e.ts +7 -2
- package/echo/client-test.ts +37 -18
- package/package.json +1 -1
- package/srpc/client.ts +9 -10
- package/srpc/common-rpc.ts +9 -11
- package/srpc/pushable.ts +2 -1
package/dist/e2e/e2e.js
CHANGED
|
@@ -13,7 +13,7 @@ async function runRPC() {
|
|
|
13
13
|
const serverConn = new StreamConn(server, { direction: 'inbound' });
|
|
14
14
|
// pipe clientConn -> messageStream -> serverConn -> messageStream -> clientConn
|
|
15
15
|
const { port1: clientPort, port2: serverPort } = new MessageChannel();
|
|
16
|
-
const opts = { idleTimeoutMs: 250, keepAliveMs: 100 }
|
|
16
|
+
const opts = {}; // { idleTimeoutMs: 250, keepAliveMs: 100 }
|
|
17
17
|
const clientChannelStream = new ChannelStream('client', clientPort, opts);
|
|
18
18
|
const serverChannelStream = new ChannelStream('server', serverPort, opts);
|
|
19
19
|
// Pipe the client traffic via the client end of the MessageChannel.
|
|
@@ -30,6 +30,10 @@ async function runRPC() {
|
|
|
30
30
|
await runClientTest(client);
|
|
31
31
|
await runAbortControllerTest(client);
|
|
32
32
|
await runRpcStreamTest(client);
|
|
33
|
+
// Make sure we have no uncaught promises
|
|
34
|
+
await new Promise((resolve) => {
|
|
35
|
+
setTimeout(resolve, 500);
|
|
36
|
+
});
|
|
33
37
|
// Close cleanly
|
|
34
38
|
clientConn.close();
|
|
35
39
|
serverConn.close();
|
|
@@ -40,6 +44,6 @@ runRPC()
|
|
|
40
44
|
process.exit(0);
|
|
41
45
|
})
|
|
42
46
|
.catch((err) => {
|
|
43
|
-
console.error(err);
|
|
47
|
+
console.error('e2e tests failed', err);
|
|
44
48
|
process.exit(1);
|
|
45
49
|
});
|
package/dist/echo/client-test.js
CHANGED
|
@@ -29,24 +29,44 @@ export async function runAbortControllerTest(client) {
|
|
|
29
29
|
const demoServiceClient = new EchoerClientImpl(client);
|
|
30
30
|
console.log('Testing EchoClientStream with AbortController...');
|
|
31
31
|
let errorReturned = false;
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const testRpc = async (rpc) => {
|
|
33
|
+
const clientAbort = new AbortController();
|
|
34
|
+
new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {
|
|
35
|
+
clientAbort.abort();
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
await rpc(clientAbort.signal);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const errMsg = err.message;
|
|
42
|
+
errorReturned = true;
|
|
43
|
+
if (errMsg !== ERR_RPC_ABORT) {
|
|
44
|
+
throw new Error('unexpected error: ' + errMsg);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!errorReturned) {
|
|
48
|
+
throw new Error('expected aborted rpc to throw error');
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
await testRpc(async (signal) => {
|
|
52
|
+
const clientNoopStream = pushable({ objectMode: true });
|
|
53
|
+
await demoServiceClient.EchoClientStream(clientNoopStream, signal);
|
|
36
54
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
throw new Error('unexpected error: ' + errMsg);
|
|
55
|
+
await testRpc(async (signal) => {
|
|
56
|
+
const stream = demoServiceClient.EchoServerStream({ body: 'test' }, signal);
|
|
57
|
+
let gotMsgs = 0;
|
|
58
|
+
try {
|
|
59
|
+
for await (const msg of stream) {
|
|
60
|
+
gotMsgs++;
|
|
61
|
+
}
|
|
45
62
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (gotMsgs < 3) {
|
|
65
|
+
throw new Error('expected at least three messages before error');
|
|
66
|
+
}
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
50
70
|
}
|
|
51
71
|
// runRpcStreamTest tests a RPCStream.
|
|
52
72
|
export async function runRpcStreamTest(client) {
|
package/dist/srpc/client.js
CHANGED
|
@@ -28,7 +28,7 @@ export class Client {
|
|
|
28
28
|
// clientStreamingRequest starts a client side streaming request.
|
|
29
29
|
async clientStreamingRequest(service, method, data, abortSignal) {
|
|
30
30
|
const call = await this.startRpc(service, method, null, abortSignal);
|
|
31
|
-
call.writeCallDataFromSource(data);
|
|
31
|
+
call.writeCallDataFromSource(data).catch((err) => call.close(err));
|
|
32
32
|
for await (const data of call.rpcDataSource) {
|
|
33
33
|
call.close();
|
|
34
34
|
return data;
|
|
@@ -41,11 +41,7 @@ export class Client {
|
|
|
41
41
|
serverStreamingRequest(service, method, data, abortSignal) {
|
|
42
42
|
const serverData = pushable({ objectMode: true });
|
|
43
43
|
this.startRpc(service, method, data, abortSignal)
|
|
44
|
-
.then(async (call) =>
|
|
45
|
-
const result = writeToPushable(call.rpcDataSource, serverData);
|
|
46
|
-
result.finally(() => call.close());
|
|
47
|
-
return result;
|
|
48
|
-
})
|
|
44
|
+
.then(async (call) => writeToPushable(call.rpcDataSource, serverData))
|
|
49
45
|
.catch((err) => serverData.end(err));
|
|
50
46
|
return serverData;
|
|
51
47
|
}
|
|
@@ -54,7 +50,11 @@ export class Client {
|
|
|
54
50
|
const serverData = pushable({ objectMode: true });
|
|
55
51
|
this.startRpc(service, method, null, abortSignal)
|
|
56
52
|
.then(async (call) => {
|
|
57
|
-
|
|
53
|
+
const handleErr = (err) => {
|
|
54
|
+
serverData.end(err);
|
|
55
|
+
call.close(err);
|
|
56
|
+
};
|
|
57
|
+
call.writeCallDataFromSource(data).catch(handleErr);
|
|
58
58
|
try {
|
|
59
59
|
for await (const message of call.rpcDataSource) {
|
|
60
60
|
serverData.push(message);
|
|
@@ -63,8 +63,7 @@ export class Client {
|
|
|
63
63
|
call.close();
|
|
64
64
|
}
|
|
65
65
|
catch (err) {
|
|
66
|
-
|
|
67
|
-
throw err;
|
|
66
|
+
handleErr(err);
|
|
68
67
|
}
|
|
69
68
|
})
|
|
70
69
|
.catch((err) => serverData.end(err));
|
|
@@ -87,7 +86,7 @@ export class Client {
|
|
|
87
86
|
pipe(stream, decodePacketSource, call, encodePacketSource, stream)
|
|
88
87
|
.catch((err) => call.close(err))
|
|
89
88
|
.then(() => call.close());
|
|
90
|
-
await call.writeCallStart(data
|
|
89
|
+
await call.writeCallStart(data ?? undefined);
|
|
91
90
|
return call;
|
|
92
91
|
}
|
|
93
92
|
}
|
|
@@ -11,6 +11,7 @@ export declare class CommonRPC {
|
|
|
11
11
|
protected method?: string;
|
|
12
12
|
private closed?;
|
|
13
13
|
constructor();
|
|
14
|
+
get isClosed(): boolean | Error;
|
|
14
15
|
writeCallData(data?: Uint8Array, complete?: boolean, error?: string): Promise<void>;
|
|
15
16
|
writeCallCancel(): Promise<void>;
|
|
16
17
|
writeCallDataFromSource(dataSource: AsyncIterable<Uint8Array>): Promise<void>;
|
|
@@ -22,6 +23,5 @@ export declare class CommonRPC {
|
|
|
22
23
|
handleCallData(packet: Partial<CallData>): Promise<void>;
|
|
23
24
|
handleCallCancel(): Promise<void>;
|
|
24
25
|
close(err?: Error): Promise<void>;
|
|
25
|
-
closeWrite(): void;
|
|
26
26
|
private _createSink;
|
|
27
27
|
}
|
package/dist/srpc/common-rpc.js
CHANGED
|
@@ -16,6 +16,10 @@ export class CommonRPC {
|
|
|
16
16
|
this.source = this._source;
|
|
17
17
|
this.rpcDataSource = this._rpcDataSource;
|
|
18
18
|
}
|
|
19
|
+
// isClosed returns one of: true (closed w/o error), Error (closed w/ error), or false (not closed).
|
|
20
|
+
get isClosed() {
|
|
21
|
+
return this.closed ?? false;
|
|
22
|
+
}
|
|
19
23
|
// writeCallData writes the call data packet.
|
|
20
24
|
async writeCallData(data, complete, error) {
|
|
21
25
|
const callData = {
|
|
@@ -130,18 +134,12 @@ export class CommonRPC {
|
|
|
130
134
|
if (this.closed) {
|
|
131
135
|
return;
|
|
132
136
|
}
|
|
133
|
-
this.closed = true;
|
|
134
|
-
// note:
|
|
135
|
-
|
|
136
|
-
await this.writeCallCancel();
|
|
137
|
-
}
|
|
137
|
+
this.closed = err ?? true;
|
|
138
|
+
// note: this does nothing if _source is already ended.
|
|
139
|
+
await this.writeCallCancel();
|
|
138
140
|
this._source.end();
|
|
139
141
|
this._rpcDataSource.end(err);
|
|
140
142
|
}
|
|
141
|
-
// closeWrite closes the call for writing.
|
|
142
|
-
closeWrite() {
|
|
143
|
-
this._source.end();
|
|
144
|
-
}
|
|
145
143
|
// _createSink returns a value for the sink field.
|
|
146
144
|
_createSink() {
|
|
147
145
|
return async (source) => {
|
package/dist/srpc/pushable.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// writeToPushable writes the incoming server data to the pushable.
|
|
2
|
+
//
|
|
3
|
+
// this will not throw an error: it instead ends out w/ the error.
|
|
2
4
|
export async function writeToPushable(dataSource, out) {
|
|
3
5
|
try {
|
|
4
6
|
for await (const data of dataSource) {
|
|
@@ -8,7 +10,6 @@ export async function writeToPushable(dataSource, out) {
|
|
|
8
10
|
}
|
|
9
11
|
catch (err) {
|
|
10
12
|
out.end(err);
|
|
11
|
-
throw err;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
export function buildPushableSink(target) {
|
package/e2e/e2e.ts
CHANGED
|
@@ -25,7 +25,7 @@ async function runRPC() {
|
|
|
25
25
|
|
|
26
26
|
// pipe clientConn -> messageStream -> serverConn -> messageStream -> clientConn
|
|
27
27
|
const { port1: clientPort, port2: serverPort } = new MessageChannel()
|
|
28
|
-
const opts: ChannelStreamOpts = { idleTimeoutMs: 250, keepAliveMs: 100 }
|
|
28
|
+
const opts: ChannelStreamOpts = {} // { idleTimeoutMs: 250, keepAliveMs: 100 }
|
|
29
29
|
const clientChannelStream = new ChannelStream('client', clientPort, opts)
|
|
30
30
|
const serverChannelStream = new ChannelStream('server', serverPort, opts)
|
|
31
31
|
|
|
@@ -57,6 +57,11 @@ async function runRPC() {
|
|
|
57
57
|
await runAbortControllerTest(client)
|
|
58
58
|
await runRpcStreamTest(client)
|
|
59
59
|
|
|
60
|
+
// Make sure we have no uncaught promises
|
|
61
|
+
await new Promise<void>((resolve) => {
|
|
62
|
+
setTimeout(resolve, 500)
|
|
63
|
+
})
|
|
64
|
+
|
|
60
65
|
// Close cleanly
|
|
61
66
|
clientConn.close()
|
|
62
67
|
serverConn.close()
|
|
@@ -68,6 +73,6 @@ runRPC()
|
|
|
68
73
|
process.exit(0)
|
|
69
74
|
})
|
|
70
75
|
.catch((err) => {
|
|
71
|
-
console.error(err)
|
|
76
|
+
console.error('e2e tests failed', err)
|
|
72
77
|
process.exit(1)
|
|
73
78
|
})
|
package/echo/client-test.ts
CHANGED
|
@@ -36,26 +36,45 @@ export async function runAbortControllerTest(client: Client) {
|
|
|
36
36
|
|
|
37
37
|
console.log('Testing EchoClientStream with AbortController...')
|
|
38
38
|
let errorReturned = false
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
|
|
40
|
+
const testRpc = async (rpc: (signal: AbortSignal) => Promise<void>) => {
|
|
41
|
+
const clientAbort = new AbortController()
|
|
42
|
+
new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {
|
|
43
|
+
clientAbort.abort()
|
|
44
|
+
})
|
|
45
|
+
try {
|
|
46
|
+
await rpc(clientAbort.signal)
|
|
47
|
+
} catch (err) {
|
|
48
|
+
const errMsg = (err as Error).message
|
|
49
|
+
errorReturned = true
|
|
50
|
+
if (errMsg !== ERR_RPC_ABORT) {
|
|
51
|
+
throw new Error('unexpected error: ' + errMsg)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!errorReturned) {
|
|
55
|
+
throw new Error('expected aborted rpc to throw error')
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
|
|
59
|
+
await testRpc(async (signal) => {
|
|
60
|
+
const clientNoopStream = pushable<EchoMsg>({ objectMode: true })
|
|
61
|
+
await demoServiceClient.EchoClientStream(clientNoopStream, signal)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
await testRpc(async (signal) => {
|
|
65
|
+
const stream = demoServiceClient.EchoServerStream({ body: 'test' }, signal)
|
|
66
|
+
let gotMsgs = 0
|
|
67
|
+
try {
|
|
68
|
+
for await (const msg of stream) {
|
|
69
|
+
gotMsgs++
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (gotMsgs < 3) {
|
|
73
|
+
throw new Error('expected at least three messages before error')
|
|
74
|
+
}
|
|
75
|
+
throw err
|
|
76
|
+
}
|
|
77
|
+
})
|
|
59
78
|
}
|
|
60
79
|
|
|
61
80
|
// runRpcStreamTest tests a RPCStream.
|
package/package.json
CHANGED
package/srpc/client.ts
CHANGED
|
@@ -48,7 +48,7 @@ export class Client implements TsProtoRpc {
|
|
|
48
48
|
abortSignal?: AbortSignal,
|
|
49
49
|
): Promise<Uint8Array> {
|
|
50
50
|
const call = await this.startRpc(service, method, null, abortSignal)
|
|
51
|
-
call.writeCallDataFromSource(data)
|
|
51
|
+
call.writeCallDataFromSource(data).catch((err) => call.close(err))
|
|
52
52
|
for await (const data of call.rpcDataSource) {
|
|
53
53
|
call.close()
|
|
54
54
|
return data
|
|
@@ -67,11 +67,7 @@ export class Client implements TsProtoRpc {
|
|
|
67
67
|
): AsyncIterable<Uint8Array> {
|
|
68
68
|
const serverData: Pushable<Uint8Array> = pushable({ objectMode: true })
|
|
69
69
|
this.startRpc(service, method, data, abortSignal)
|
|
70
|
-
.then(async (call) =>
|
|
71
|
-
const result = writeToPushable(call.rpcDataSource, serverData)
|
|
72
|
-
result.finally(() => call.close())
|
|
73
|
-
return result
|
|
74
|
-
})
|
|
70
|
+
.then(async (call) => writeToPushable(call.rpcDataSource, serverData))
|
|
75
71
|
.catch((err) => serverData.end(err))
|
|
76
72
|
return serverData
|
|
77
73
|
}
|
|
@@ -86,7 +82,11 @@ export class Client implements TsProtoRpc {
|
|
|
86
82
|
const serverData: Pushable<Uint8Array> = pushable({ objectMode: true })
|
|
87
83
|
this.startRpc(service, method, null, abortSignal)
|
|
88
84
|
.then(async (call) => {
|
|
89
|
-
|
|
85
|
+
const handleErr = (err: Error) => {
|
|
86
|
+
serverData.end(err)
|
|
87
|
+
call.close(err)
|
|
88
|
+
}
|
|
89
|
+
call.writeCallDataFromSource(data).catch(handleErr)
|
|
90
90
|
try {
|
|
91
91
|
for await (const message of call.rpcDataSource) {
|
|
92
92
|
serverData.push(message)
|
|
@@ -94,8 +94,7 @@ export class Client implements TsProtoRpc {
|
|
|
94
94
|
serverData.end()
|
|
95
95
|
call.close()
|
|
96
96
|
} catch (err) {
|
|
97
|
-
|
|
98
|
-
throw err
|
|
97
|
+
handleErr(err as Error)
|
|
99
98
|
}
|
|
100
99
|
})
|
|
101
100
|
.catch((err) => serverData.end(err))
|
|
@@ -124,7 +123,7 @@ export class Client implements TsProtoRpc {
|
|
|
124
123
|
pipe(stream, decodePacketSource, call, encodePacketSource, stream)
|
|
125
124
|
.catch((err) => call.close(err))
|
|
126
125
|
.then(() => call.close())
|
|
127
|
-
await call.writeCallStart(data
|
|
126
|
+
await call.writeCallStart(data ?? undefined)
|
|
128
127
|
return call
|
|
129
128
|
}
|
|
130
129
|
}
|
package/srpc/common-rpc.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class CommonRPC {
|
|
|
30
30
|
protected method?: string
|
|
31
31
|
|
|
32
32
|
// closed indicates this rpc has been closed already.
|
|
33
|
-
private closed?:
|
|
33
|
+
private closed?: true | Error
|
|
34
34
|
|
|
35
35
|
constructor() {
|
|
36
36
|
this.sink = this._createSink()
|
|
@@ -38,6 +38,11 @@ export class CommonRPC {
|
|
|
38
38
|
this.rpcDataSource = this._rpcDataSource
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// isClosed returns one of: true (closed w/o error), Error (closed w/ error), or false (not closed).
|
|
42
|
+
public get isClosed(): boolean | Error {
|
|
43
|
+
return this.closed ?? false
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
// writeCallData writes the call data packet.
|
|
42
47
|
public async writeCallData(
|
|
43
48
|
data?: Uint8Array,
|
|
@@ -168,20 +173,13 @@ export class CommonRPC {
|
|
|
168
173
|
if (this.closed) {
|
|
169
174
|
return
|
|
170
175
|
}
|
|
171
|
-
this.closed = true
|
|
172
|
-
// note:
|
|
173
|
-
|
|
174
|
-
await this.writeCallCancel()
|
|
175
|
-
}
|
|
176
|
+
this.closed = err ?? true
|
|
177
|
+
// note: this does nothing if _source is already ended.
|
|
178
|
+
await this.writeCallCancel()
|
|
176
179
|
this._source.end()
|
|
177
180
|
this._rpcDataSource.end(err)
|
|
178
181
|
}
|
|
179
182
|
|
|
180
|
-
// closeWrite closes the call for writing.
|
|
181
|
-
public closeWrite() {
|
|
182
|
-
this._source.end()
|
|
183
|
-
}
|
|
184
|
-
|
|
185
183
|
// _createSink returns a value for the sink field.
|
|
186
184
|
private _createSink(): Sink<Source<Packet>> {
|
|
187
185
|
return async (source: Source<Packet>) => {
|
package/srpc/pushable.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { Pushable } from 'it-pushable'
|
|
|
2
2
|
import { Sink, Source } from 'it-stream-types'
|
|
3
3
|
|
|
4
4
|
// writeToPushable writes the incoming server data to the pushable.
|
|
5
|
+
//
|
|
6
|
+
// this will not throw an error: it instead ends out w/ the error.
|
|
5
7
|
export async function writeToPushable<T>(
|
|
6
8
|
dataSource: AsyncIterable<T>,
|
|
7
9
|
out: Pushable<T>,
|
|
@@ -13,7 +15,6 @@ export async function writeToPushable<T>(
|
|
|
13
15
|
out.end()
|
|
14
16
|
} catch (err) {
|
|
15
17
|
out.end(err as Error)
|
|
16
|
-
throw err
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|