starpc 0.14.0 → 0.14.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/srpc/client.d.ts +2 -4
- package/dist/srpc/client.js +4 -32
- package/dist/srpc/index.d.ts +2 -0
- package/dist/srpc/index.js +2 -0
- package/dist/srpc/open-stream-ctr.d.ts +6 -0
- package/dist/srpc/open-stream-ctr.js +17 -0
- package/dist/srpc/value-ctr.d.ts +9 -0
- package/dist/srpc/value-ctr.js +44 -0
- package/package.json +1 -1
- package/srpc/client.ts +7 -37
- package/srpc/index.ts +2 -0
- package/srpc/muxed-conn.go +1 -0
- package/srpc/open-stream-ctr.ts +20 -0
- package/srpc/packet-rw.go +1 -1
- package/srpc/value-ctr.ts +54 -0
- package/srpc/websocket.go +8 -53
package/dist/srpc/client.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { TsProtoRpc } from './ts-proto-rpc.js';
|
|
2
2
|
import type { OpenStreamFunc } from './stream.js';
|
|
3
3
|
export declare class Client implements TsProtoRpc {
|
|
4
|
-
private
|
|
5
|
-
private _openStreamFn?;
|
|
4
|
+
private openStreamCtr;
|
|
6
5
|
constructor(openStreamFn?: OpenStreamFunc);
|
|
7
|
-
setOpenStreamFn(openStreamFn?: OpenStreamFunc):
|
|
8
|
-
private initOpenStreamFn;
|
|
6
|
+
setOpenStreamFn(openStreamFn?: OpenStreamFunc): void;
|
|
9
7
|
request(service: string, method: string, data: Uint8Array): Promise<Uint8Array>;
|
|
10
8
|
clientStreamingRequest(service: string, method: string, data: AsyncIterable<Uint8Array>): Promise<Uint8Array>;
|
|
11
9
|
serverStreamingRequest(service: string, method: string, data: Uint8Array): AsyncIterable<Uint8Array>;
|
package/dist/srpc/client.js
CHANGED
|
@@ -4,43 +4,15 @@ import { ClientRPC } from './client-rpc.js';
|
|
|
4
4
|
import { writeToPushable } from './pushable.js';
|
|
5
5
|
import { decodePacketSource, encodePacketSource, parseLengthPrefixTransform, prependLengthPrefixTransform, } from './packet.js';
|
|
6
6
|
import { combineUint8ArrayListTransform } from './array-list.js';
|
|
7
|
+
import { OpenStreamCtr } from './open-stream-ctr.js';
|
|
7
8
|
// Client implements the ts-proto Rpc interface with the drpcproto protocol.
|
|
8
9
|
export class Client {
|
|
9
10
|
constructor(openStreamFn) {
|
|
10
|
-
this.
|
|
11
|
+
this.openStreamCtr = new OpenStreamCtr(openStreamFn || undefined);
|
|
11
12
|
}
|
|
12
13
|
// setOpenStreamFn updates the openStreamFn for the Client.
|
|
13
14
|
setOpenStreamFn(openStreamFn) {
|
|
14
|
-
|
|
15
|
-
if (openStreamFn) {
|
|
16
|
-
this._openStreamFn(openStreamFn);
|
|
17
|
-
this._openStreamFn = undefined;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
if (openStreamFn) {
|
|
22
|
-
this.openStreamFn = Promise.resolve(openStreamFn);
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
this.initOpenStreamFn();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return this.openStreamFn;
|
|
29
|
-
}
|
|
30
|
-
// initOpenStreamFn creates the empty Promise for openStreamFn.
|
|
31
|
-
initOpenStreamFn() {
|
|
32
|
-
const openPromise = new Promise((resolve, reject) => {
|
|
33
|
-
this._openStreamFn = (conn, err) => {
|
|
34
|
-
if (err) {
|
|
35
|
-
reject(err);
|
|
36
|
-
}
|
|
37
|
-
else if (conn) {
|
|
38
|
-
resolve(conn);
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
this.openStreamFn = openPromise;
|
|
43
|
-
return this.openStreamFn;
|
|
15
|
+
this.openStreamCtr.set(openStreamFn || undefined);
|
|
44
16
|
}
|
|
45
17
|
// request starts a non-streaming request.
|
|
46
18
|
async request(service, method, data) {
|
|
@@ -98,7 +70,7 @@ export class Client {
|
|
|
98
70
|
// throws any error starting the rpc call
|
|
99
71
|
// if data == null and data.length == 0, sends a separate data packet.
|
|
100
72
|
async startRpc(rpcService, rpcMethod, data) {
|
|
101
|
-
const openStreamFn = await this.
|
|
73
|
+
const openStreamFn = await this.openStreamCtr.wait();
|
|
102
74
|
const conn = await openStreamFn();
|
|
103
75
|
const call = new ClientRPC(rpcService, rpcMethod);
|
|
104
76
|
pipe(conn, parseLengthPrefixTransform(), combineUint8ArrayListTransform(), decodePacketSource, call, encodePacketSource, prependLengthPrefixTransform(), conn);
|
package/dist/srpc/index.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export { Packet, CallStart, CallData } from './rpcproto.pb.js';
|
|
|
7
7
|
export { Mux, StaticMux, 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 { ValueCtr } from './value-ctr.js';
|
|
11
|
+
export { OpenStreamCtr } from './open-stream-ctr.js';
|
|
10
12
|
export { writeToPushable } from './pushable';
|
package/dist/srpc/index.js
CHANGED
|
@@ -6,4 +6,6 @@ export { Packet, CallStart, CallData } from './rpcproto.pb.js';
|
|
|
6
6
|
export { StaticMux, 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 { ValueCtr } from './value-ctr.js';
|
|
10
|
+
export { OpenStreamCtr } from './open-stream-ctr.js';
|
|
9
11
|
export { writeToPushable } from './pushable';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ValueCtr } from './value-ctr.js';
|
|
2
|
+
// OpenStreamCtr contains an OpenStream func which can be awaited.
|
|
3
|
+
export class OpenStreamCtr extends ValueCtr {
|
|
4
|
+
constructor(openStreamFn) {
|
|
5
|
+
super(openStreamFn);
|
|
6
|
+
}
|
|
7
|
+
// openStreamFunc returns an OpenStreamFunc which waits for the underlying OpenStreamFunc.
|
|
8
|
+
get openStreamFunc() {
|
|
9
|
+
return async () => {
|
|
10
|
+
let openFn = this.value;
|
|
11
|
+
if (!openFn) {
|
|
12
|
+
openFn = await this.wait();
|
|
13
|
+
}
|
|
14
|
+
return openFn();
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ValueCtr contains a value that can be set asynchronously.
|
|
2
|
+
export class ValueCtr {
|
|
3
|
+
constructor(initialValue) {
|
|
4
|
+
this._value = initialValue || undefined;
|
|
5
|
+
this._waiters = [];
|
|
6
|
+
}
|
|
7
|
+
// value returns the current value.
|
|
8
|
+
get value() {
|
|
9
|
+
return this._value;
|
|
10
|
+
}
|
|
11
|
+
// wait waits for the value to not be undefined.
|
|
12
|
+
async wait() {
|
|
13
|
+
const currVal = this._value;
|
|
14
|
+
if (currVal !== undefined) {
|
|
15
|
+
return currVal;
|
|
16
|
+
}
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
this.waitWithCb((val) => {
|
|
19
|
+
resolve(val);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// waitWithCb adds a callback to be called when the value is not undefined.
|
|
24
|
+
waitWithCb(cb) {
|
|
25
|
+
if (cb) {
|
|
26
|
+
this._waiters.push(cb);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// set sets the value and calls the callbacks.
|
|
30
|
+
set(val) {
|
|
31
|
+
this._value = val;
|
|
32
|
+
if (val === undefined) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const waiters = this._waiters;
|
|
36
|
+
if (waiters.length === 0) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this._waiters = [];
|
|
40
|
+
for (const waiter of waiters) {
|
|
41
|
+
waiter(val);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
package/package.json
CHANGED
package/srpc/client.ts
CHANGED
|
@@ -12,50 +12,20 @@ import {
|
|
|
12
12
|
prependLengthPrefixTransform,
|
|
13
13
|
} from './packet.js'
|
|
14
14
|
import { combineUint8ArrayListTransform } from './array-list.js'
|
|
15
|
+
import { OpenStreamCtr } from './open-stream-ctr.js'
|
|
15
16
|
|
|
16
17
|
// Client implements the ts-proto Rpc interface with the drpcproto protocol.
|
|
17
18
|
export class Client implements TsProtoRpc {
|
|
18
|
-
//
|
|
19
|
-
private
|
|
20
|
-
// _openStreamFn resolves openStreamFn.
|
|
21
|
-
private _openStreamFn?: (conn?: OpenStreamFunc, err?: Error) => void
|
|
19
|
+
// openStreamCtr contains the OpenStreamFunc.
|
|
20
|
+
private openStreamCtr: OpenStreamCtr
|
|
22
21
|
|
|
23
22
|
constructor(openStreamFn?: OpenStreamFunc) {
|
|
24
|
-
this.
|
|
23
|
+
this.openStreamCtr = new OpenStreamCtr(openStreamFn || undefined)
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
// setOpenStreamFn updates the openStreamFn for the Client.
|
|
28
|
-
public setOpenStreamFn(
|
|
29
|
-
openStreamFn
|
|
30
|
-
): Promise<OpenStreamFunc> {
|
|
31
|
-
if (this._openStreamFn) {
|
|
32
|
-
if (openStreamFn) {
|
|
33
|
-
this._openStreamFn(openStreamFn)
|
|
34
|
-
this._openStreamFn = undefined
|
|
35
|
-
}
|
|
36
|
-
} else {
|
|
37
|
-
if (openStreamFn) {
|
|
38
|
-
this.openStreamFn = Promise.resolve(openStreamFn)
|
|
39
|
-
} else {
|
|
40
|
-
this.initOpenStreamFn()
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return this.openStreamFn
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// initOpenStreamFn creates the empty Promise for openStreamFn.
|
|
47
|
-
private initOpenStreamFn(): Promise<OpenStreamFunc> {
|
|
48
|
-
const openPromise = new Promise<OpenStreamFunc>((resolve, reject) => {
|
|
49
|
-
this._openStreamFn = (conn?: OpenStreamFunc, err?: Error) => {
|
|
50
|
-
if (err) {
|
|
51
|
-
reject(err)
|
|
52
|
-
} else if (conn) {
|
|
53
|
-
resolve(conn)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
this.openStreamFn = openPromise
|
|
58
|
-
return this.openStreamFn
|
|
27
|
+
public setOpenStreamFn(openStreamFn?: OpenStreamFunc) {
|
|
28
|
+
this.openStreamCtr.set(openStreamFn || undefined)
|
|
59
29
|
}
|
|
60
30
|
|
|
61
31
|
// request starts a non-streaming request.
|
|
@@ -137,7 +107,7 @@ export class Client implements TsProtoRpc {
|
|
|
137
107
|
rpcMethod: string,
|
|
138
108
|
data: Uint8Array | null
|
|
139
109
|
): Promise<ClientRPC> {
|
|
140
|
-
const openStreamFn = await this.
|
|
110
|
+
const openStreamFn = await this.openStreamCtr.wait()
|
|
141
111
|
const conn = await openStreamFn()
|
|
142
112
|
const call = new ClientRPC(rpcService, rpcMethod)
|
|
143
113
|
pipe(
|
package/srpc/index.ts
CHANGED
package/srpc/muxed-conn.go
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OpenStreamFunc, Stream } from './stream.js'
|
|
2
|
+
import { ValueCtr } from './value-ctr.js'
|
|
3
|
+
|
|
4
|
+
// OpenStreamCtr contains an OpenStream func which can be awaited.
|
|
5
|
+
export class OpenStreamCtr extends ValueCtr<OpenStreamFunc> {
|
|
6
|
+
constructor(openStreamFn?: OpenStreamFunc) {
|
|
7
|
+
super(openStreamFn)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// openStreamFunc returns an OpenStreamFunc which waits for the underlying OpenStreamFunc.
|
|
11
|
+
get openStreamFunc(): OpenStreamFunc {
|
|
12
|
+
return async (): Promise<Stream> => {
|
|
13
|
+
let openFn = this.value
|
|
14
|
+
if (!openFn) {
|
|
15
|
+
openFn = await this.wait()
|
|
16
|
+
}
|
|
17
|
+
return openFn()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
package/srpc/packet-rw.go
CHANGED
|
@@ -94,7 +94,7 @@ func (r *PacketReaderWriter) ReadToHandler(cb PacketHandler) error {
|
|
|
94
94
|
|
|
95
95
|
// parse the length prefix if not done already
|
|
96
96
|
if currLen == 0 {
|
|
97
|
-
currLen = r.readLengthPrefix(r.buf.Bytes())
|
|
97
|
+
currLen = r.readLengthPrefix(r.buf.Bytes()[:4])
|
|
98
98
|
if currLen == 0 {
|
|
99
99
|
return errors.New("unexpected zero len prefix")
|
|
100
100
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// ValueCtr contains a value that can be set asynchronously.
|
|
2
|
+
export class ValueCtr<T> {
|
|
3
|
+
// _value contains the current value.
|
|
4
|
+
private _value: T | undefined
|
|
5
|
+
// _waiters contains the list of waiters.
|
|
6
|
+
// called when the value is set to any value other than undefined.
|
|
7
|
+
private _waiters: ((fn: T) => void)[]
|
|
8
|
+
|
|
9
|
+
constructor(initialValue?: T) {
|
|
10
|
+
this._value = initialValue || undefined
|
|
11
|
+
this._waiters = []
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// value returns the current value.
|
|
15
|
+
get value(): T | undefined {
|
|
16
|
+
return this._value
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// wait waits for the value to not be undefined.
|
|
20
|
+
public async wait(): Promise<T> {
|
|
21
|
+
const currVal = this._value
|
|
22
|
+
if (currVal !== undefined) {
|
|
23
|
+
return currVal
|
|
24
|
+
}
|
|
25
|
+
return new Promise<T>((resolve) => {
|
|
26
|
+
this.waitWithCb((val: T) => {
|
|
27
|
+
resolve(val)
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// waitWithCb adds a callback to be called when the value is not undefined.
|
|
33
|
+
public waitWithCb(cb: (val: T) => void) {
|
|
34
|
+
if (cb) {
|
|
35
|
+
this._waiters.push(cb)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// set sets the value and calls the callbacks.
|
|
40
|
+
public set(val: T | undefined) {
|
|
41
|
+
this._value = val
|
|
42
|
+
if (val === undefined) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
const waiters = this._waiters
|
|
46
|
+
if (waiters.length === 0) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
this._waiters = []
|
|
50
|
+
for (const waiter of waiters) {
|
|
51
|
+
waiter(val)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
package/srpc/websocket.go
CHANGED
|
@@ -2,65 +2,20 @@ package srpc
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"context"
|
|
5
|
-
"io"
|
|
6
5
|
|
|
7
6
|
"github.com/libp2p/go-libp2p/core/network"
|
|
8
7
|
"github.com/libp2p/go-yamux/v4"
|
|
9
8
|
"nhooyr.io/websocket"
|
|
10
9
|
)
|
|
11
10
|
|
|
12
|
-
//
|
|
13
|
-
type WebSocketConn struct {
|
|
14
|
-
// conn is the websocket conn
|
|
15
|
-
conn *websocket.Conn
|
|
16
|
-
// mconn is the muxed conn
|
|
17
|
-
mconn network.MuxedConn
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// NewWebSocketConn constructs a new WebSocket connection.
|
|
21
|
-
//
|
|
11
|
+
// NewWebSocketConn wraps a websocket into a MuxedConn.
|
|
22
12
|
// if yamuxConf is unset, uses the defaults.
|
|
23
|
-
func NewWebSocketConn(
|
|
13
|
+
func NewWebSocketConn(
|
|
14
|
+
ctx context.Context,
|
|
15
|
+
conn *websocket.Conn,
|
|
16
|
+
isServer bool,
|
|
17
|
+
yamuxConf *yamux.Config,
|
|
18
|
+
) (network.MuxedConn, error) {
|
|
24
19
|
nc := websocket.NetConn(ctx, conn, websocket.MessageBinary)
|
|
25
|
-
|
|
26
|
-
if err != nil {
|
|
27
|
-
return nil, err
|
|
28
|
-
}
|
|
29
|
-
return &WebSocketConn{conn: conn, mconn: muxedConn}, nil
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// GetWebSocket returns the web socket conn.
|
|
33
|
-
func (w *WebSocketConn) GetWebSocket() *websocket.Conn {
|
|
34
|
-
return w.conn
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// GetOpenStreamFunc returns the OpenStream func.
|
|
38
|
-
func (w *WebSocketConn) GetOpenStreamFunc() OpenStreamFunc {
|
|
39
|
-
return w.OpenStream
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// AcceptStream accepts an incoming stream.
|
|
43
|
-
func (w *WebSocketConn) AcceptStream() (io.ReadWriteCloser, error) {
|
|
44
|
-
strm, err := w.mconn.AcceptStream()
|
|
45
|
-
if err != nil {
|
|
46
|
-
return nil, err
|
|
47
|
-
}
|
|
48
|
-
return strm, nil
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// OpenStream tries to open a stream with the remote.
|
|
52
|
-
func (w *WebSocketConn) OpenStream(ctx context.Context, msgHandler PacketHandler, closeHandler CloseHandler) (Writer, error) {
|
|
53
|
-
muxedStream, err := w.mconn.OpenStream(ctx)
|
|
54
|
-
if err != nil {
|
|
55
|
-
return nil, err
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
rw := NewPacketReadWriter(muxedStream)
|
|
59
|
-
go rw.ReadPump(msgHandler, closeHandler)
|
|
60
|
-
return rw, nil
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Close closes the writer.
|
|
64
|
-
func (w *WebSocketConn) Close() error {
|
|
65
|
-
return w.conn.Close(websocket.StatusGoingAway, "conn closed")
|
|
20
|
+
return NewMuxedConn(nc, !isServer, yamuxConf)
|
|
66
21
|
}
|