starpc 0.25.0 → 0.25.1
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 +20 -2
- package/dist/srpc/channel.d.ts +10 -6
- package/dist/srpc/channel.js +9 -9
- package/e2e/e2e.ts +23 -2
- package/package.json +1 -1
- package/srpc/channel.ts +28 -16
package/dist/e2e/e2e.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pipe } from 'it-pipe';
|
|
2
|
-
import { createHandler, createMux, Server, Client, StreamConn } from '../srpc';
|
|
2
|
+
import { createHandler, createMux, Server, Client, StreamConn, ChannelStream, combineUint8ArrayListTransform } from '../srpc';
|
|
3
3
|
import { EchoerDefinition, EchoerServer, runClientTest } from '../echo';
|
|
4
4
|
import { runAbortControllerTest, runRpcStreamTest } from '../echo/client-test';
|
|
5
5
|
async function runRPC() {
|
|
@@ -7,13 +7,31 @@ async function runRPC() {
|
|
|
7
7
|
const server = new Server(mux.lookupMethodFunc);
|
|
8
8
|
const echoer = new EchoerServer(server);
|
|
9
9
|
mux.register(createHandler(EchoerDefinition, echoer));
|
|
10
|
+
// StreamConn is unnecessary since ChannelStream has packet framing.
|
|
11
|
+
// Use it here to include yamux in this e2e test.
|
|
10
12
|
const clientConn = new StreamConn();
|
|
11
13
|
const serverConn = new StreamConn(server, { direction: 'inbound' });
|
|
12
|
-
pipe
|
|
14
|
+
// pipe clientConn -> messageStream -> serverConn -> messageStream -> clientConn
|
|
15
|
+
const { port1: clientPort, port2: serverPort } = new MessageChannel();
|
|
16
|
+
const clientChannelStream = new ChannelStream('client', clientPort);
|
|
17
|
+
const serverChannelStream = new ChannelStream('server', serverPort);
|
|
18
|
+
// Pipe the client traffic via the client end of the MessageChannel.
|
|
19
|
+
pipe(clientChannelStream, clientConn, combineUint8ArrayListTransform(), clientChannelStream)
|
|
20
|
+
.catch((err) => clientConn.close(err))
|
|
21
|
+
.then(() => clientConn.close());
|
|
22
|
+
// Pipe the server traffic via the server end of the MessageChannel.
|
|
23
|
+
pipe(serverChannelStream, serverConn, combineUint8ArrayListTransform(), serverChannelStream)
|
|
24
|
+
.catch((err) => serverConn.close(err))
|
|
25
|
+
.then(() => serverConn.close());
|
|
26
|
+
// Build the client
|
|
13
27
|
const client = new Client(clientConn.buildOpenStreamFunc());
|
|
28
|
+
// Run the tests
|
|
14
29
|
await runClientTest(client);
|
|
15
30
|
await runAbortControllerTest(client);
|
|
16
31
|
await runRpcStreamTest(client);
|
|
32
|
+
// Close cleanly
|
|
33
|
+
clientConn.close();
|
|
34
|
+
serverConn.close();
|
|
17
35
|
}
|
|
18
36
|
runRPC()
|
|
19
37
|
.then(() => {
|
package/dist/srpc/channel.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Sink, Source, Duplex } from 'it-stream-types';
|
|
2
2
|
export interface ChannelStreamMessage<T> {
|
|
3
3
|
from: string;
|
|
4
|
-
ack?:
|
|
5
|
-
opened?:
|
|
6
|
-
|
|
4
|
+
ack?: true;
|
|
5
|
+
opened?: true;
|
|
6
|
+
alive?: true;
|
|
7
|
+
closed?: true;
|
|
7
8
|
error?: Error;
|
|
8
9
|
data?: T;
|
|
9
10
|
}
|
|
@@ -11,7 +12,10 @@ export type ChannelPort = MessagePort | {
|
|
|
11
12
|
tx: BroadcastChannel;
|
|
12
13
|
rx: BroadcastChannel;
|
|
13
14
|
};
|
|
14
|
-
export
|
|
15
|
+
export interface ChannelStreamOpts {
|
|
16
|
+
remoteOpen?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class ChannelStream<T = Uint8Array> implements Duplex<AsyncGenerator<T>, Source<T>, Promise<void>> {
|
|
15
19
|
readonly channel: ChannelPort;
|
|
16
20
|
sink: Sink<Source<T>, Promise<void>>;
|
|
17
21
|
source: AsyncGenerator<T>;
|
|
@@ -26,7 +30,7 @@ export declare class ChannelStream<T> implements Duplex<AsyncGenerator<T>, Sourc
|
|
|
26
30
|
private _remoteAck?;
|
|
27
31
|
get isAcked(): boolean;
|
|
28
32
|
get isOpen(): boolean;
|
|
29
|
-
constructor(localId: string, channel: ChannelPort,
|
|
33
|
+
constructor(localId: string, channel: ChannelPort, opts?: ChannelStreamOpts);
|
|
30
34
|
private postMessage;
|
|
31
35
|
close(error?: Error): void;
|
|
32
36
|
private onLocalOpened;
|
|
@@ -35,4 +39,4 @@ export declare class ChannelStream<T> implements Duplex<AsyncGenerator<T>, Sourc
|
|
|
35
39
|
private _createSink;
|
|
36
40
|
private onMessage;
|
|
37
41
|
}
|
|
38
|
-
export declare function newBroadcastChannelStream<T>(id: string, readName: string, writeName: string,
|
|
42
|
+
export declare function newBroadcastChannelStream<T>(id: string, readName: string, writeName: string, opts?: ChannelStreamOpts): ChannelStream<T>;
|
package/dist/srpc/channel.js
CHANGED
|
@@ -7,21 +7,21 @@ import { pushable } from 'it-pushable';
|
|
|
7
7
|
export class ChannelStream {
|
|
8
8
|
// isAcked checks if the stream is acknowledged by the remote.
|
|
9
9
|
get isAcked() {
|
|
10
|
-
return this.remoteAck
|
|
10
|
+
return this.remoteAck ?? false;
|
|
11
11
|
}
|
|
12
12
|
// isOpen checks if the stream is opened by the remote.
|
|
13
13
|
get isOpen() {
|
|
14
|
-
return this.remoteOpen
|
|
14
|
+
return this.remoteOpen ?? false;
|
|
15
15
|
}
|
|
16
|
-
// remoteOpen indicates
|
|
17
|
-
constructor(localId, channel,
|
|
16
|
+
// remoteOpen indicates that we know the remote has already opened the stream.
|
|
17
|
+
constructor(localId, channel, opts) {
|
|
18
18
|
this.localId = localId;
|
|
19
19
|
this.channel = channel;
|
|
20
20
|
this.sink = this._createSink();
|
|
21
21
|
this.localOpen = false;
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
if (remoteOpen) {
|
|
22
|
+
this.remoteOpen = opts?.remoteOpen ?? false;
|
|
23
|
+
this.remoteAck = this.remoteOpen;
|
|
24
|
+
if (this.remoteOpen) {
|
|
25
25
|
this.waitRemoteOpen = Promise.resolve();
|
|
26
26
|
this.waitRemoteAck = Promise.resolve();
|
|
27
27
|
}
|
|
@@ -159,6 +159,6 @@ export class ChannelStream {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
// newBroadcastChannelStream constructs a ChannelStream with a channel name.
|
|
162
|
-
export function newBroadcastChannelStream(id, readName, writeName,
|
|
163
|
-
return new ChannelStream(id, { tx: new BroadcastChannel(writeName), rx: new BroadcastChannel(readName) },
|
|
162
|
+
export function newBroadcastChannelStream(id, readName, writeName, opts) {
|
|
163
|
+
return new ChannelStream(id, { tx: new BroadcastChannel(writeName), rx: new BroadcastChannel(readName) }, opts);
|
|
164
164
|
}
|
package/e2e/e2e.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pipe } from 'it-pipe'
|
|
2
|
-
import { createHandler, createMux, Server, Client, StreamConn } from '../srpc'
|
|
2
|
+
import { createHandler, createMux, Server, Client, StreamConn, ChannelStream, combineUint8ArrayListTransform } from '../srpc'
|
|
3
3
|
import { EchoerDefinition, EchoerServer, runClientTest } from '../echo'
|
|
4
4
|
import { runAbortControllerTest, runRpcStreamTest } from '../echo/client-test'
|
|
5
5
|
|
|
@@ -9,16 +9,37 @@ async function runRPC() {
|
|
|
9
9
|
const echoer = new EchoerServer(server)
|
|
10
10
|
mux.register(createHandler(EchoerDefinition, echoer))
|
|
11
11
|
|
|
12
|
+
// StreamConn is unnecessary since ChannelStream has packet framing.
|
|
13
|
+
// Use it here to include yamux in this e2e test.
|
|
12
14
|
const clientConn = new StreamConn()
|
|
13
15
|
const serverConn = new StreamConn(server, { direction: 'inbound' })
|
|
14
16
|
|
|
15
|
-
pipe
|
|
17
|
+
// pipe clientConn -> messageStream -> serverConn -> messageStream -> clientConn
|
|
18
|
+
const {port1: clientPort, port2: serverPort} = new MessageChannel()
|
|
19
|
+
const clientChannelStream = new ChannelStream('client', clientPort)
|
|
20
|
+
const serverChannelStream = new ChannelStream('server', serverPort)
|
|
16
21
|
|
|
22
|
+
// Pipe the client traffic via the client end of the MessageChannel.
|
|
23
|
+
pipe(clientChannelStream, clientConn, combineUint8ArrayListTransform(), clientChannelStream)
|
|
24
|
+
.catch((err: Error) => clientConn.close(err))
|
|
25
|
+
.then(() => clientConn.close())
|
|
26
|
+
|
|
27
|
+
// Pipe the server traffic via the server end of the MessageChannel.
|
|
28
|
+
pipe(serverChannelStream, serverConn, combineUint8ArrayListTransform(), serverChannelStream)
|
|
29
|
+
.catch((err: Error) => serverConn.close(err))
|
|
30
|
+
.then(() => serverConn.close())
|
|
31
|
+
|
|
32
|
+
// Build the client
|
|
17
33
|
const client = new Client(clientConn.buildOpenStreamFunc())
|
|
18
34
|
|
|
35
|
+
// Run the tests
|
|
19
36
|
await runClientTest(client)
|
|
20
37
|
await runAbortControllerTest(client)
|
|
21
38
|
await runRpcStreamTest(client)
|
|
39
|
+
|
|
40
|
+
// Close cleanly
|
|
41
|
+
clientConn.close()
|
|
42
|
+
serverConn.close()
|
|
22
43
|
}
|
|
23
44
|
|
|
24
45
|
runRPC()
|
package/package.json
CHANGED
package/srpc/channel.ts
CHANGED
|
@@ -5,27 +5,39 @@ import { pushable, Pushable } from 'it-pushable'
|
|
|
5
5
|
export interface ChannelStreamMessage<T> {
|
|
6
6
|
// from indicates who sent the message.
|
|
7
7
|
from: string
|
|
8
|
-
// ack indicates a remote
|
|
9
|
-
ack?:
|
|
8
|
+
// ack indicates a remote acked establishing the stream.
|
|
9
|
+
ack?: true
|
|
10
10
|
// opened indicates the remote has opened the stream.
|
|
11
|
-
opened?:
|
|
11
|
+
opened?: true
|
|
12
|
+
// alive indicates this is a keep-alive packet.
|
|
13
|
+
// not set unless keep-alives are enabled.
|
|
14
|
+
alive?: true
|
|
12
15
|
// closed indicates the stream is closed.
|
|
13
|
-
closed?:
|
|
16
|
+
closed?: true
|
|
14
17
|
// error indicates the stream has an error.
|
|
15
18
|
error?: Error
|
|
16
19
|
// data is any message data.
|
|
17
20
|
data?: T
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
//
|
|
21
|
-
export type ChannelPort =
|
|
23
|
+
// ChannelPort represents a channel we can open a stream over.
|
|
24
|
+
export type ChannelPort =
|
|
25
|
+
| MessagePort
|
|
26
|
+
| { tx: BroadcastChannel; rx: BroadcastChannel }
|
|
27
|
+
|
|
28
|
+
// ChannelStreamOpts are options for ChannelStream.
|
|
29
|
+
export interface ChannelStreamOpts {
|
|
30
|
+
// remoteOpen indicates that the remote already knows the channel is open.
|
|
31
|
+
// this skips sending and waiting for the open+ack messages.
|
|
32
|
+
remoteOpen?: boolean
|
|
33
|
+
}
|
|
22
34
|
|
|
23
35
|
// ChannelStream implements a Stream over a BroadcastChannel duplex or MessagePort.
|
|
24
36
|
//
|
|
25
37
|
// NOTE: there is no way to tell if a BroadcastChannel or MessagePort is closed.
|
|
26
38
|
// This implementation sends a "closed" message when close() is called.
|
|
27
39
|
// However: if the remote is removed w/o closing cleanly, the stream will be left open!
|
|
28
|
-
export class ChannelStream<T>
|
|
40
|
+
export class ChannelStream<T = Uint8Array>
|
|
29
41
|
implements Duplex<AsyncGenerator<T>, Source<T>, Promise<void>>
|
|
30
42
|
{
|
|
31
43
|
// channel is the read/write channel.
|
|
@@ -58,24 +70,24 @@ export class ChannelStream<T>
|
|
|
58
70
|
|
|
59
71
|
// isAcked checks if the stream is acknowledged by the remote.
|
|
60
72
|
public get isAcked() {
|
|
61
|
-
return this.remoteAck
|
|
73
|
+
return this.remoteAck ?? false
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
// isOpen checks if the stream is opened by the remote.
|
|
65
77
|
public get isOpen() {
|
|
66
|
-
return this.remoteOpen
|
|
78
|
+
return this.remoteOpen ?? false
|
|
67
79
|
}
|
|
68
80
|
|
|
69
|
-
// remoteOpen indicates
|
|
70
|
-
constructor(localId: string, channel: ChannelPort,
|
|
81
|
+
// remoteOpen indicates that we know the remote has already opened the stream.
|
|
82
|
+
constructor(localId: string, channel: ChannelPort, opts?: ChannelStreamOpts) {
|
|
71
83
|
this.localId = localId
|
|
72
84
|
this.channel = channel
|
|
73
85
|
this.sink = this._createSink()
|
|
74
86
|
|
|
75
87
|
this.localOpen = false
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
78
|
-
if (remoteOpen) {
|
|
88
|
+
this.remoteOpen = opts?.remoteOpen ?? false
|
|
89
|
+
this.remoteAck = this.remoteOpen
|
|
90
|
+
if (this.remoteOpen) {
|
|
79
91
|
this.waitRemoteOpen = Promise.resolve()
|
|
80
92
|
this.waitRemoteAck = Promise.resolve()
|
|
81
93
|
} else {
|
|
@@ -220,11 +232,11 @@ export function newBroadcastChannelStream<T>(
|
|
|
220
232
|
id: string,
|
|
221
233
|
readName: string,
|
|
222
234
|
writeName: string,
|
|
223
|
-
|
|
235
|
+
opts?: ChannelStreamOpts,
|
|
224
236
|
): ChannelStream<T> {
|
|
225
237
|
return new ChannelStream<T>(
|
|
226
238
|
id,
|
|
227
239
|
{ tx: new BroadcastChannel(writeName), rx: new BroadcastChannel(readName) },
|
|
228
|
-
|
|
240
|
+
opts,
|
|
229
241
|
)
|
|
230
242
|
}
|