starpc 0.3.6 → 0.4.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.
Files changed (56) hide show
  1. package/Makefile +22 -13
  2. package/README.md +4 -0
  3. package/dist/echo/client-test.js +1 -1
  4. package/dist/echo/{echo.d.ts → echo.pb.d.ts} +0 -0
  5. package/dist/echo/{echo.js → echo.pb.js} +0 -0
  6. package/dist/echo/index.d.ts +1 -1
  7. package/dist/echo/index.js +1 -1
  8. package/dist/echo/server.d.ts +1 -1
  9. package/dist/rpcstream/rpcstream.d.ts +19 -0
  10. package/dist/rpcstream/rpcstream.js +94 -0
  11. package/dist/rpcstream/rpcstream.pb.d.ts +85 -0
  12. package/dist/rpcstream/rpcstream.pb.js +160 -0
  13. package/dist/srpc/client-rpc.d.ts +1 -1
  14. package/dist/srpc/client.d.ts +5 -5
  15. package/dist/srpc/client.js +19 -19
  16. package/dist/srpc/common-rpc.d.ts +2 -2
  17. package/dist/srpc/common-rpc.js +1 -1
  18. package/dist/srpc/conn.d.ts +1 -1
  19. package/dist/srpc/index.d.ts +2 -1
  20. package/dist/srpc/index.js +1 -0
  21. package/dist/srpc/observable-source.d.ts +9 -0
  22. package/dist/srpc/observable-source.js +25 -0
  23. package/dist/srpc/packet.d.ts +1 -1
  24. package/dist/srpc/packet.js +1 -1
  25. package/dist/srpc/{rpcproto.d.ts → rpcproto.pb.d.ts} +0 -0
  26. package/dist/srpc/{rpcproto.js → rpcproto.pb.js} +0 -0
  27. package/dist/srpc/server-rpc.d.ts +1 -1
  28. package/dist/srpc/server.d.ts +4 -4
  29. package/dist/srpc/server.js +6 -5
  30. package/dist/srpc/stream.d.ts +1 -1
  31. package/echo/client-test.ts +1 -1
  32. package/echo/{echo.ts → echo.pb.ts} +0 -0
  33. package/echo/index.ts +1 -1
  34. package/echo/server.ts +1 -1
  35. package/integration/integration.ts +2 -2
  36. package/package.json +4 -3
  37. package/srpc/broadcast-channel.ts +1 -1
  38. package/srpc/client-rpc.ts +1 -1
  39. package/srpc/client.go +2 -2
  40. package/srpc/client.ts +25 -23
  41. package/srpc/common-rpc.ts +2 -2
  42. package/srpc/conn.ts +1 -1
  43. package/srpc/index.ts +2 -2
  44. package/srpc/{rpc-stream.go → msg-stream.go} +11 -11
  45. package/srpc/muxed-conn.go +1 -1
  46. package/srpc/observable-source.ts +40 -0
  47. package/srpc/packet.ts +1 -1
  48. package/srpc/{rpcproto.ts → rpcproto.pb.ts} +0 -0
  49. package/srpc/server-pipe.go +1 -1
  50. package/srpc/server-rpc.go +1 -1
  51. package/srpc/server-rpc.ts +1 -1
  52. package/srpc/server.go +5 -0
  53. package/srpc/server.ts +8 -7
  54. package/srpc/stream.ts +1 -1
  55. package/srpc/websocket.go +1 -1
  56. package/e2e/debug.test +0 -0
package/Makefile CHANGED
@@ -1,13 +1,18 @@
1
+ # https://github.com/aperturerobotics/protobuf-project
2
+
1
3
  PROTOWRAP=hack/bin/protowrap
2
4
  PROTOC_GEN_GO=hack/bin/protoc-gen-go
5
+ PROTOC_GEN_GO_STARPC=hack/bin/protoc-gen-go-starpc
3
6
  PROTOC_GEN_VTPROTO=hack/bin/protoc-gen-go-vtproto
4
- PROTOC_GEN_STARPC=hack/bin/protoc-gen-go-starpc
5
7
  GOIMPORTS=hack/bin/goimports
6
8
  GOLANGCI_LINT=hack/bin/golangci-lint
7
9
  GO_MOD_OUTDATED=hack/bin/go-mod-outdated
8
- export GO111MODULE=on
9
10
  GOLIST=go list -f "{{ .Dir }}" -m
10
11
 
12
+ export GO111MODULE=on
13
+ undefine GOARCH
14
+ undefine GOOS
15
+
11
16
  all:
12
17
 
13
18
  vendor:
@@ -17,19 +22,19 @@ $(PROTOC_GEN_GO):
17
22
  cd ./hack; \
18
23
  go build -v \
19
24
  -o ./bin/protoc-gen-go \
20
- github.com/golang/protobuf/protoc-gen-go
25
+ google.golang.org/protobuf/cmd/protoc-gen-go
21
26
 
22
- $(PROTOC_GEN_VTPROTO):
27
+ $(PROTOC_GEN_GO_STARPC):
23
28
  cd ./hack; \
24
29
  go build -v \
25
- -o ./bin/protoc-gen-go-vtproto \
26
- github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
30
+ -o ./bin/protoc-gen-go-starpc \
31
+ github.com/aperturerobotics/starpc/cmd/protoc-gen-go-starpc
27
32
 
28
- $(PROTOC_GEN_STARPC):
33
+ $(PROTOC_GEN_VTPROTO):
29
34
  cd ./hack; \
30
35
  go build -v \
31
- -o ./bin/protoc-gen-go-starpc \
32
- github.com/aperturerobotics/starpc/cmd/protoc-gen-go-starpc
36
+ -o ./bin/protoc-gen-go-vtproto \
37
+ github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
33
38
 
34
39
  $(GOIMPORTS):
35
40
  cd ./hack; \
@@ -56,7 +61,7 @@ $(GO_MOD_OUTDATED):
56
61
  github.com/psampaz/go-mod-outdated
57
62
 
58
63
  .PHONY: gengo
59
- gengo: $(GOIMPORTS) $(PROTOWRAP) $(PROTOC_GEN_GO) $(PROTOC_GEN_VTPROTO) $(PROTOC_GEN_STARPC)
64
+ gengo: $(GOIMPORTS) $(PROTOWRAP) $(PROTOC_GEN_GO) $(PROTOC_GEN_GO_STARPC) $(PROTOC_GEN_VTPROTO)
60
65
  go mod vendor
61
66
  shopt -s globstar; \
62
67
  set -eo pipefail; \
@@ -99,9 +104,10 @@ gents: $(PROTOWRAP) node_modules
99
104
  -I $$(pwd)/vendor \
100
105
  --plugin=./node_modules/.bin/protoc-gen-ts_proto \
101
106
  --ts_proto_out=$$(pwd)/vendor \
107
+ --ts_proto_opt=esModuleInterop=true \
108
+ --ts_proto_opt=fileSuffix=.pb \
102
109
  --ts_proto_opt=forceLong=long \
103
110
  --ts_proto_opt=oneof=unions \
104
- --ts_proto_opt=esModuleInterop=true \
105
111
  --ts_proto_opt=outputServices=default,outputServices=generic-definitions \
106
112
  --proto_path $$(pwd)/vendor \
107
113
  --print_structure \
@@ -119,15 +125,19 @@ genproto: gengo gents
119
125
  .PHONY: gen
120
126
  gen: genproto
121
127
 
128
+ .PHONY: outdated
122
129
  outdated: $(GO_MOD_OUTDATED)
123
130
  go list -mod=mod -u -m -json all | $(GO_MOD_OUTDATED) -update -direct
124
131
 
132
+ .PHONY: list
125
133
  list: $(GO_MOD_OUTDATED)
126
134
  go list -mod=mod -u -m -json all | $(GO_MOD_OUTDATED)
127
135
 
136
+ .PHONY: lint
128
137
  lint: $(GOLANGCI_LINT)
129
138
  $(GOLANGCI_LINT) run
130
139
 
140
+ .PHONY: fix
131
141
  fix: $(GOLANGCI_LINT)
132
142
  $(GOLANGCI_LINT) run --fix
133
143
 
@@ -137,5 +147,4 @@ test:
137
147
 
138
148
  .PHONY: integration
139
149
  integration: node_modules vendor
140
- cd ./integration && \
141
- bash ./integration.bash
150
+ cd ./integration && bash ./integration.bash
package/README.md CHANGED
@@ -13,6 +13,10 @@ Can use any Stream multiplexer: defaults to [libp2p-mplex] over a WebSocket.
13
13
 
14
14
  [libp2p-mplex]: https://github.com/libp2p/js-libp2p-mplex
15
15
 
16
+ [rpcstream] supports sub-streams for per-component sub-services.
17
+
18
+ [rpcstream]: ./rpcstream
19
+
16
20
  # Usage
17
21
 
18
22
  Starting with the [protobuf-project] repository on the "starpc" branch.
@@ -1,4 +1,4 @@
1
- import { EchoerClientImpl } from './echo.js';
1
+ import { EchoerClientImpl } from './echo.pb.js';
2
2
  import { Observable } from 'rxjs';
3
3
  export async function runClientTest(client) {
4
4
  const demoServiceClient = new EchoerClientImpl(client);
File without changes
File without changes
@@ -1,3 +1,3 @@
1
- export * from './echo.js';
1
+ export * from './echo.pb.js';
2
2
  export * from './server.js';
3
3
  export { runClientTest } from './client-test.js';
@@ -1,3 +1,3 @@
1
- export * from './echo.js';
1
+ export * from './echo.pb.js';
2
2
  export * from './server.js';
3
3
  export { runClientTest } from './client-test.js';
@@ -1,5 +1,5 @@
1
1
  import { Observable } from 'rxjs';
2
- import { Echoer, EchoMsg } from './echo';
2
+ import { Echoer, EchoMsg } from './echo.pb.js';
3
3
  export declare class EchoerServer implements Echoer {
4
4
  Echo(request: EchoMsg): Promise<EchoMsg>;
5
5
  EchoServerStream(request: EchoMsg): Observable<EchoMsg>;
@@ -0,0 +1,19 @@
1
+ import { Observable } from 'rxjs';
2
+ import { Packet } from './rpcstream.pb.js';
3
+ import { Server } from '../srpc/server.js';
4
+ import { OpenStreamFunc, Stream } from '../srpc/stream.js';
5
+ import { Pushable } from 'it-pushable';
6
+ import { Source, Sink } from 'it-stream-types';
7
+ export declare type RpcStreamCaller = (request: Observable<Packet>) => Observable<Packet>;
8
+ export declare function buildRpcStreamOpenStream(componentId: string, caller: RpcStreamCaller): OpenStreamFunc;
9
+ export declare type RpcStreamGetter = (componentId: string) => Promise<Server>;
10
+ export declare function handleRpcStream(stream: Observable<Packet>, getter: RpcStreamGetter): AsyncIterable<Packet>;
11
+ export declare class RpcStream implements Stream {
12
+ readonly source: Source<Uint8Array>;
13
+ readonly sink: Sink<Uint8Array>;
14
+ private readonly _packetSink;
15
+ private readonly _source;
16
+ constructor(packetSink: Pushable<Packet>, packetSource: Observable<Packet>);
17
+ private _createSink;
18
+ private _subscribePacketSource;
19
+ }
@@ -0,0 +1,94 @@
1
+ import { from as obsFrom } from 'rxjs';
2
+ import { pushable } from 'it-pushable';
3
+ // buildRpcStreamOpenStream builds a OpenStream func with a RpcStream.
4
+ export function buildRpcStreamOpenStream(componentId, caller) {
5
+ return async () => {
6
+ const packetSink = pushable({ objectMode: true });
7
+ const packetObs = obsFrom(packetSink);
8
+ const packetSource = caller(packetObs);
9
+ // write the component id
10
+ packetSink.push({
11
+ body: {
12
+ $case: 'init',
13
+ init: { componentId },
14
+ }
15
+ });
16
+ // build & return the stream
17
+ return new RpcStream(packetSink, packetSource);
18
+ };
19
+ }
20
+ // handleRpcStream handles an incoming RPC stream (remote is the initiator).
21
+ export async function* handleRpcStream(stream, getter) {
22
+ // read the component id
23
+ const initPromise = new Promise((resolve, reject) => {
24
+ const subscription = stream.subscribe({
25
+ next(value) {
26
+ resolve(value);
27
+ subscription.unsubscribe();
28
+ },
29
+ error(err) {
30
+ reject(err);
31
+ },
32
+ complete() {
33
+ reject(new Error('no packet received'));
34
+ },
35
+ });
36
+ });
37
+ // read the init packet
38
+ const initPacket = await initPromise;
39
+ if (initPacket?.body?.$case !== 'init') {
40
+ throw new Error('expected init packet');
41
+ }
42
+ // lookup the server for the component id.
43
+ const server = await getter(initPacket.body.init.componentId);
44
+ // build the outgoing packet sink & the packet source
45
+ const packetSink = pushable({ objectMode: true });
46
+ // handle the stream
47
+ const rpcStream = new RpcStream(packetSink, stream);
48
+ server.handleDuplex(rpcStream);
49
+ // return the outgoing packet sink
50
+ return packetSink;
51
+ }
52
+ // RpcStream implements the Stream on top of a RPC call.
53
+ export class RpcStream {
54
+ constructor(packetSink, packetSource) {
55
+ this._packetSink = packetSink;
56
+ this.sink = this._createSink();
57
+ const source = pushable({ objectMode: true });
58
+ this.source = source;
59
+ this._source = source;
60
+ this._subscribePacketSource(packetSource);
61
+ }
62
+ // _createSink initializes the sink field.
63
+ _createSink() {
64
+ return async (source) => {
65
+ try {
66
+ for await (const msg of source) {
67
+ this._packetSink.push({
68
+ body: { $case: 'data', data: msg }
69
+ });
70
+ }
71
+ this._packetSink.end();
72
+ }
73
+ catch (err) {
74
+ this._packetSink.end(err);
75
+ }
76
+ };
77
+ }
78
+ // _subscribePacketSource starts the subscription to the response data.
79
+ _subscribePacketSource(packetSource) {
80
+ packetSource.subscribe({
81
+ next: (value) => {
82
+ if (value?.body?.$case === 'data') {
83
+ this._source.push(value.body.data);
84
+ }
85
+ },
86
+ error: (err) => {
87
+ this._source.end(err);
88
+ },
89
+ complete: () => {
90
+ this._source.end();
91
+ },
92
+ });
93
+ }
94
+ }
@@ -0,0 +1,85 @@
1
+ import Long from 'long';
2
+ import * as _m0 from 'protobufjs/minimal';
3
+ export declare const protobufPackage = "rpcstream";
4
+ /** Packet is a packet encapsulating data for a RPC stream. */
5
+ export interface Packet {
6
+ body?: {
7
+ $case: 'init';
8
+ init: RpcStreamInit;
9
+ } | {
10
+ $case: 'data';
11
+ data: Uint8Array;
12
+ };
13
+ }
14
+ /** RpcStreamInit is the first message in a RPC stream. */
15
+ export interface RpcStreamInit {
16
+ /** ComponentId is the identifier of the component making the request. */
17
+ componentId: string;
18
+ }
19
+ export declare const Packet: {
20
+ encode(message: Packet, writer?: _m0.Writer): _m0.Writer;
21
+ decode(input: _m0.Reader | Uint8Array, length?: number): Packet;
22
+ fromJSON(object: any): Packet;
23
+ toJSON(message: Packet): unknown;
24
+ fromPartial<I extends {
25
+ body?: ({
26
+ init?: {
27
+ componentId?: string | undefined;
28
+ } | undefined;
29
+ } & {
30
+ $case: "init";
31
+ }) | ({
32
+ data?: Uint8Array | undefined;
33
+ } & {
34
+ $case: "data";
35
+ }) | undefined;
36
+ } & {
37
+ body?: ({
38
+ init?: {
39
+ componentId?: string | undefined;
40
+ } | undefined;
41
+ } & {
42
+ $case: "init";
43
+ } & {
44
+ init?: ({
45
+ componentId?: string | undefined;
46
+ } & {
47
+ componentId?: string | undefined;
48
+ } & Record<Exclude<keyof I["body"]["init"], "componentId">, never>) | undefined;
49
+ $case: "init";
50
+ } & Record<Exclude<keyof I["body"], "$case" | "init">, never>) | ({
51
+ data?: Uint8Array | undefined;
52
+ } & {
53
+ $case: "data";
54
+ } & {
55
+ data?: Uint8Array | undefined;
56
+ $case: "data";
57
+ } & Record<Exclude<keyof I["body"], "$case" | "data">, never>) | undefined;
58
+ } & Record<Exclude<keyof I, "body">, never>>(object: I): Packet;
59
+ };
60
+ export declare const RpcStreamInit: {
61
+ encode(message: RpcStreamInit, writer?: _m0.Writer): _m0.Writer;
62
+ decode(input: _m0.Reader | Uint8Array, length?: number): RpcStreamInit;
63
+ fromJSON(object: any): RpcStreamInit;
64
+ toJSON(message: RpcStreamInit): unknown;
65
+ fromPartial<I extends {
66
+ componentId?: string | undefined;
67
+ } & {
68
+ componentId?: string | undefined;
69
+ } & Record<Exclude<keyof I, "componentId">, never>>(object: I): RpcStreamInit;
70
+ };
71
+ declare type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
72
+ export declare type DeepPartial<T> = T extends Builtin ? T : T extends Long ? string | number | Long : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {
73
+ $case: string;
74
+ } ? {
75
+ [K in keyof Omit<T, '$case'>]?: DeepPartial<T[K]>;
76
+ } & {
77
+ $case: T['$case'];
78
+ } : T extends {} ? {
79
+ [K in keyof T]?: DeepPartial<T[K]>;
80
+ } : Partial<T>;
81
+ declare type KeysOfUnion<T> = T extends T ? keyof T : never;
82
+ export declare type Exact<P, I extends P> = P extends Builtin ? P : P & {
83
+ [K in keyof P]: Exact<P[K], I[K]>;
84
+ } & Record<Exclude<keyof I, KeysOfUnion<P>>, never>;
85
+ export {};
@@ -0,0 +1,160 @@
1
+ /* eslint-disable */
2
+ import Long from 'long';
3
+ import * as _m0 from 'protobufjs/minimal';
4
+ export const protobufPackage = 'rpcstream';
5
+ function createBasePacket() {
6
+ return { body: undefined };
7
+ }
8
+ export const Packet = {
9
+ encode(message, writer = _m0.Writer.create()) {
10
+ if (message.body?.$case === 'init') {
11
+ RpcStreamInit.encode(message.body.init, writer.uint32(10).fork()).ldelim();
12
+ }
13
+ if (message.body?.$case === 'data') {
14
+ writer.uint32(18).bytes(message.body.data);
15
+ }
16
+ return writer;
17
+ },
18
+ decode(input, length) {
19
+ const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
20
+ let end = length === undefined ? reader.len : reader.pos + length;
21
+ const message = createBasePacket();
22
+ while (reader.pos < end) {
23
+ const tag = reader.uint32();
24
+ switch (tag >>> 3) {
25
+ case 1:
26
+ message.body = {
27
+ $case: 'init',
28
+ init: RpcStreamInit.decode(reader, reader.uint32()),
29
+ };
30
+ break;
31
+ case 2:
32
+ message.body = { $case: 'data', data: reader.bytes() };
33
+ break;
34
+ default:
35
+ reader.skipType(tag & 7);
36
+ break;
37
+ }
38
+ }
39
+ return message;
40
+ },
41
+ fromJSON(object) {
42
+ return {
43
+ body: isSet(object.init)
44
+ ? { $case: 'init', init: RpcStreamInit.fromJSON(object.init) }
45
+ : isSet(object.data)
46
+ ? { $case: 'data', data: bytesFromBase64(object.data) }
47
+ : undefined,
48
+ };
49
+ },
50
+ toJSON(message) {
51
+ const obj = {};
52
+ message.body?.$case === 'init' &&
53
+ (obj.init = message.body?.init
54
+ ? RpcStreamInit.toJSON(message.body?.init)
55
+ : undefined);
56
+ message.body?.$case === 'data' &&
57
+ (obj.data =
58
+ message.body?.data !== undefined
59
+ ? base64FromBytes(message.body?.data)
60
+ : undefined);
61
+ return obj;
62
+ },
63
+ fromPartial(object) {
64
+ const message = createBasePacket();
65
+ if (object.body?.$case === 'init' &&
66
+ object.body?.init !== undefined &&
67
+ object.body?.init !== null) {
68
+ message.body = {
69
+ $case: 'init',
70
+ init: RpcStreamInit.fromPartial(object.body.init),
71
+ };
72
+ }
73
+ if (object.body?.$case === 'data' &&
74
+ object.body?.data !== undefined &&
75
+ object.body?.data !== null) {
76
+ message.body = { $case: 'data', data: object.body.data };
77
+ }
78
+ return message;
79
+ },
80
+ };
81
+ function createBaseRpcStreamInit() {
82
+ return { componentId: '' };
83
+ }
84
+ export const RpcStreamInit = {
85
+ encode(message, writer = _m0.Writer.create()) {
86
+ if (message.componentId !== '') {
87
+ writer.uint32(10).string(message.componentId);
88
+ }
89
+ return writer;
90
+ },
91
+ decode(input, length) {
92
+ const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
93
+ let end = length === undefined ? reader.len : reader.pos + length;
94
+ const message = createBaseRpcStreamInit();
95
+ while (reader.pos < end) {
96
+ const tag = reader.uint32();
97
+ switch (tag >>> 3) {
98
+ case 1:
99
+ message.componentId = reader.string();
100
+ break;
101
+ default:
102
+ reader.skipType(tag & 7);
103
+ break;
104
+ }
105
+ }
106
+ return message;
107
+ },
108
+ fromJSON(object) {
109
+ return {
110
+ componentId: isSet(object.componentId) ? String(object.componentId) : '',
111
+ };
112
+ },
113
+ toJSON(message) {
114
+ const obj = {};
115
+ message.componentId !== undefined && (obj.componentId = message.componentId);
116
+ return obj;
117
+ },
118
+ fromPartial(object) {
119
+ const message = createBaseRpcStreamInit();
120
+ message.componentId = object.componentId ?? '';
121
+ return message;
122
+ },
123
+ };
124
+ var globalThis = (() => {
125
+ if (typeof globalThis !== 'undefined')
126
+ return globalThis;
127
+ if (typeof self !== 'undefined')
128
+ return self;
129
+ if (typeof window !== 'undefined')
130
+ return window;
131
+ if (typeof global !== 'undefined')
132
+ return global;
133
+ throw 'Unable to locate global object';
134
+ })();
135
+ const atob = globalThis.atob ||
136
+ ((b64) => globalThis.Buffer.from(b64, 'base64').toString('binary'));
137
+ function bytesFromBase64(b64) {
138
+ const bin = atob(b64);
139
+ const arr = new Uint8Array(bin.length);
140
+ for (let i = 0; i < bin.length; ++i) {
141
+ arr[i] = bin.charCodeAt(i);
142
+ }
143
+ return arr;
144
+ }
145
+ const btoa = globalThis.btoa ||
146
+ ((bin) => globalThis.Buffer.from(bin, 'binary').toString('base64'));
147
+ function base64FromBytes(arr) {
148
+ const bin = [];
149
+ arr.forEach((byte) => {
150
+ bin.push(String.fromCharCode(byte));
151
+ });
152
+ return btoa(bin.join(''));
153
+ }
154
+ if (_m0.util.Long !== Long) {
155
+ _m0.util.Long = Long;
156
+ _m0.configure();
157
+ }
158
+ function isSet(value) {
159
+ return value !== null && value !== undefined;
160
+ }
@@ -1,4 +1,4 @@
1
- import type { CallStart } from './rpcproto.js';
1
+ import type { CallStart } from './rpcproto.pb.js';
2
2
  import { CommonRPC } from './common-rpc.js';
3
3
  export declare class ClientRPC extends CommonRPC {
4
4
  constructor(service: string, method: string);
@@ -2,11 +2,11 @@ import { Observable } from 'rxjs';
2
2
  import type { TsProtoRpc } from './ts-proto-rpc.js';
3
3
  import type { OpenStreamFunc } from './stream.js';
4
4
  export declare class Client implements TsProtoRpc {
5
- private openConnFn;
6
- private _openConnFn?;
7
- constructor(openConnFn?: OpenStreamFunc);
8
- setOpenConnFn(openConnFn?: OpenStreamFunc): Promise<OpenStreamFunc>;
9
- private initOpenConnFn;
5
+ private openStreamFn;
6
+ private _openStreamFn?;
7
+ constructor(openStreamFn?: OpenStreamFunc);
8
+ setOpenStreamFn(openStreamFn?: OpenStreamFunc): Promise<OpenStreamFunc>;
9
+ private initOpenStreamFn;
10
10
  request(service: string, method: string, data: Uint8Array): Promise<Uint8Array>;
11
11
  clientStreamingRequest(service: string, method: string, data: Observable<Uint8Array>): Promise<Uint8Array>;
12
12
  serverStreamingRequest(service: string, method: string, data: Uint8Array): Observable<Uint8Array>;
@@ -19,31 +19,31 @@ function writeClientStream(call, data) {
19
19
  }
20
20
  // Client implements the ts-proto Rpc interface with the drpcproto protocol.
21
21
  export class Client {
22
- constructor(openConnFn) {
23
- this.openConnFn = this.setOpenConnFn(openConnFn);
22
+ constructor(openStreamFn) {
23
+ this.openStreamFn = this.setOpenStreamFn(openStreamFn);
24
24
  }
25
- // setOpenConnFn updates the openConnFn for the Client.
26
- setOpenConnFn(openConnFn) {
27
- if (this._openConnFn) {
28
- if (openConnFn) {
29
- this._openConnFn(openConnFn);
30
- this._openConnFn = undefined;
25
+ // setOpenStreamFn updates the openStreamFn for the Client.
26
+ setOpenStreamFn(openStreamFn) {
27
+ if (this._openStreamFn) {
28
+ if (openStreamFn) {
29
+ this._openStreamFn(openStreamFn);
30
+ this._openStreamFn = undefined;
31
31
  }
32
32
  }
33
33
  else {
34
- if (openConnFn) {
35
- this.openConnFn = Promise.resolve(openConnFn);
34
+ if (openStreamFn) {
35
+ this.openStreamFn = Promise.resolve(openStreamFn);
36
36
  }
37
37
  else {
38
- this.initOpenConnFn();
38
+ this.initOpenStreamFn();
39
39
  }
40
40
  }
41
- return this.openConnFn;
41
+ return this.openStreamFn;
42
42
  }
43
- // initOpenConnFn creates the empty Promise for openConnFn.
44
- initOpenConnFn() {
43
+ // initOpenStreamFn creates the empty Promise for openStreamFn.
44
+ initOpenStreamFn() {
45
45
  const openPromise = new Promise((resolve, reject) => {
46
- this._openConnFn = (conn, err) => {
46
+ this._openStreamFn = (conn, err) => {
47
47
  if (err) {
48
48
  reject(err);
49
49
  }
@@ -52,8 +52,8 @@ export class Client {
52
52
  }
53
53
  };
54
54
  });
55
- this.openConnFn = openPromise;
56
- return this.openConnFn;
55
+ this.openStreamFn = openPromise;
56
+ return this.openStreamFn;
57
57
  }
58
58
  // request starts a non-streaming request.
59
59
  async request(service, method, data) {
@@ -131,8 +131,8 @@ export class Client {
131
131
  // throws any error starting the rpc call
132
132
  // if data == null and data.length == 0, sends a separate data packet.
133
133
  async startRpc(rpcService, rpcMethod, data) {
134
- const openConnFn = await this.openConnFn;
135
- const conn = await openConnFn();
134
+ const openStreamFn = await this.openStreamFn;
135
+ const conn = await openStreamFn();
136
136
  const call = new ClientRPC(rpcService, rpcMethod);
137
137
  pipe(conn, parseLengthPrefixTransform(), decodePacketSource, call, encodePacketSource, prependLengthPrefixTransform(), conn);
138
138
  await call.writeCallStart(data || undefined);
@@ -1,6 +1,6 @@
1
1
  import type { Source, Sink } from 'it-stream-types';
2
- import type { CallData, CallStart } from './rpcproto.js';
3
- import { Packet } from './rpcproto.js';
2
+ import type { CallData, CallStart } from './rpcproto.pb.js';
3
+ import { Packet } from './rpcproto.pb.js';
4
4
  export declare class CommonRPC {
5
5
  sink: Sink<Packet>;
6
6
  source: AsyncIterable<Packet>;
@@ -1,5 +1,5 @@
1
1
  import { pushable } from 'it-pushable';
2
- import { Packet } from './rpcproto.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  // CommonRPC is common logic between server and client RPCs.
4
4
  export class CommonRPC {
5
5
  constructor() {
@@ -7,7 +7,7 @@ export interface ConnParams {
7
7
  muxerFactory?: StreamMuxerFactory;
8
8
  }
9
9
  export interface StreamHandler {
10
- handleStream(strm: Duplex<Uint8Array>): Promise<void>;
10
+ handleStream(strm: Duplex<Uint8Array>): void;
11
11
  }
12
12
  export declare class Conn implements Duplex<Uint8Array> {
13
13
  private muxer;
@@ -1,4 +1,4 @@
1
- export type { OpenStreamFunc } from './stream.js';
1
+ export type { PacketHandler, Stream, OpenStreamFunc } from './stream.js';
2
2
  export { Client } from './client.js';
3
3
  export { Server } from './server.js';
4
4
  export { Conn, ConnParams } from './conn.js';
@@ -6,3 +6,4 @@ export { Handler, InvokeFn, createHandler, createInvokeFn } from './handler.js';
6
6
  export { Mux, createMux } from './mux.js';
7
7
  export { BroadcastChannelIterable, newBroadcastChannelIterable, BroadcastChannelConn, } from './broadcast-channel.js';
8
8
  export { MessagePortIterable, newMessagePortIterable, MessagePortConn, } from './message-port.js';
9
+ export { ObservableSource } from './observable-source.js';
@@ -5,3 +5,4 @@ export { createHandler, createInvokeFn } from './handler.js';
5
5
  export { createMux } from './mux.js';
6
6
  export { BroadcastChannelIterable, newBroadcastChannelIterable, BroadcastChannelConn, } from './broadcast-channel.js';
7
7
  export { MessagePortIterable, newMessagePortIterable, MessagePortConn, } from './message-port.js';
8
+ export { ObservableSource } from './observable-source.js';
@@ -0,0 +1,9 @@
1
+ import { Source } from 'it-stream-types';
2
+ import { Observable } from 'rxjs';
3
+ export declare class ObservableSource<T> {
4
+ readonly source: Source<T>;
5
+ private readonly _source;
6
+ private readonly subscription;
7
+ constructor(observable: Observable<T>);
8
+ close(err?: Error): void;
9
+ }
@@ -0,0 +1,25 @@
1
+ import { pushable } from 'it-pushable';
2
+ // ObservableSource wraps an Observable into a Source.
3
+ export class ObservableSource {
4
+ constructor(observable) {
5
+ const source = pushable({ objectMode: true });
6
+ this.source = source;
7
+ this._source = source;
8
+ this.subscription = observable.subscribe({
9
+ next: (value) => {
10
+ this._source.push(value);
11
+ },
12
+ error: (err) => {
13
+ this._source.end(err);
14
+ },
15
+ complete: () => {
16
+ this._source.end();
17
+ },
18
+ });
19
+ }
20
+ // close closes the subscription.
21
+ close(err) {
22
+ this._source.end(err);
23
+ this.subscription.unsubscribe();
24
+ }
25
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Transform } from 'it-stream-types';
2
- import { Packet } from './rpcproto.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  export declare const decodePacketSource: (source: import("it-stream-types").Source<Uint8Array | Uint8Array[]>) => AsyncIterable<Packet>;
4
4
  export declare const encodePacketSource: (source: import("it-stream-types").Source<Packet | Packet[]>) => AsyncIterable<Uint8Array>;
5
5
  export declare function prependLengthPrefixTransform(): Transform<Uint8Array>;
@@ -1,5 +1,5 @@
1
1
  import { encode as lengthPrefixEncode, decode as lengthPrefixDecode, } from 'it-length-prefixed';
2
- import { Packet } from './rpcproto.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  import { buildDecodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
4
4
  // decodePacketSource decodes packets from a binary data stream.
5
5
  export const decodePacketSource = buildDecodeMessageTransform(Packet);
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- import type { CallData, CallStart } from './rpcproto.js';
1
+ import type { CallData, CallStart } from './rpcproto.pb.js';
2
2
  import { CommonRPC } from './common-rpc.js';
3
3
  import { Mux } from './mux.js';
4
4
  export declare class ServerRPC extends CommonRPC {
@@ -2,13 +2,13 @@ import { Stream } from '@libp2p/interface-connection';
2
2
  import { Duplex } from 'it-stream-types';
3
3
  import { Mux } from './mux.js';
4
4
  import { ServerRPC } from './server-rpc.js';
5
- import { Packet } from './rpcproto.js';
5
+ import { Packet } from './rpcproto.pb.js';
6
6
  import { StreamHandler } from './conn.js';
7
7
  export declare class Server implements StreamHandler {
8
8
  private mux;
9
9
  constructor(mux: Mux);
10
10
  startRpc(): ServerRPC;
11
- handleStream(stream: Stream): Promise<void>;
12
- handleDuplex(stream: Duplex<Uint8Array>): Promise<void>;
13
- handlePacketStream(stream: Duplex<Packet>): Promise<void>;
11
+ handleStream(stream: Stream): ServerRPC;
12
+ handleDuplex(stream: Duplex<Uint8Array>): ServerRPC;
13
+ handlePacketStream(stream: Duplex<Packet>): ServerRPC;
14
14
  }
@@ -12,18 +12,19 @@ export class Server {
12
12
  return new ServerRPC(this.mux);
13
13
  }
14
14
  // handleStream handles an incoming Uint8Array message duplex.
15
- // closes the stream when the rpc completes.
16
15
  handleStream(stream) {
17
16
  return this.handleDuplex(stream);
18
17
  }
19
18
  // handleDuplex handles an incoming message duplex.
20
- async handleDuplex(stream) {
19
+ handleDuplex(stream) {
21
20
  const rpc = this.startRpc();
22
- await pipe(stream, parseLengthPrefixTransform(), decodePacketSource, rpc, encodePacketSource, prependLengthPrefixTransform(), stream);
21
+ pipe(stream, parseLengthPrefixTransform(), decodePacketSource, rpc, encodePacketSource, prependLengthPrefixTransform(), stream);
22
+ return rpc;
23
23
  }
24
24
  // handlePacketStream handles an incoming Packet duplex.
25
- async handlePacketStream(stream) {
25
+ handlePacketStream(stream) {
26
26
  const rpc = this.startRpc();
27
- await pipe(stream, rpc, stream);
27
+ pipe(stream, rpc, stream);
28
+ return rpc;
28
29
  }
29
30
  }
@@ -1,4 +1,4 @@
1
- import type { Packet } from './rpcproto';
1
+ import type { Packet } from './rpcproto.pb.js';
2
2
  import type { Duplex } from 'it-stream-types';
3
3
  export declare type PacketHandler = (packet: Packet) => Promise<void>;
4
4
  export declare type Stream = Duplex<Uint8Array>;
@@ -1,5 +1,5 @@
1
1
  import { Client } from '../srpc/index.js'
2
- import { EchoerClientImpl, EchoMsg } from './echo.js'
2
+ import { EchoerClientImpl, EchoMsg } from './echo.pb.js'
3
3
  import { Observable } from 'rxjs'
4
4
 
5
5
  export async function runClientTest(client: Client) {
File without changes
package/echo/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './echo.js'
1
+ export * from './echo.pb.js'
2
2
  export * from './server.js'
3
3
  export { runClientTest } from './client-test.js'
package/echo/server.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Observable, from as observableFrom } from 'rxjs'
2
- import { Echoer, EchoMsg } from './echo'
2
+ import { Echoer, EchoMsg } from './echo.pb.js'
3
3
  import { pushable, Pushable } from 'it-pushable'
4
4
 
5
5
  // EchoServer implements the Echoer server.
@@ -1,5 +1,5 @@
1
- import { WebSocketConn } from '../srpc/websocket'
2
- import { runClientTest } from '../echo'
1
+ import { WebSocketConn } from '../srpc/websocket.js'
2
+ import { runClientTest } from '../echo/client-test.js'
3
3
  import WebSocket from 'isomorphic-ws'
4
4
 
5
5
  async function runRPC() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.3.6",
3
+ "version": "0.4.2",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -22,6 +22,7 @@
22
22
  "Makefile",
23
23
  "dist/echo",
24
24
  "dist/srpc",
25
+ "dist/rpcstream",
25
26
  "e2e",
26
27
  "echo",
27
28
  "go.mod",
@@ -39,7 +40,7 @@
39
40
  "deps": "depcheck",
40
41
  "codegen": "npm run gen",
41
42
  "ci": "npm run build && npm run lint:js && npm run lint:go",
42
- "format": "prettier --write './{srpc,echo,e2e,integration}/**/(*.ts|*.tsx|*.html|*.css)'",
43
+ "format": "prettier --write './{srpc,echo,e2e,integration,rpcstream}/**/(*.ts|*.tsx|*.html|*.css)'",
43
44
  "gen": "make genproto",
44
45
  "test": "npm run test:js && npm run test:go",
45
46
  "test:go": "make test",
@@ -48,7 +49,7 @@
48
49
  "integration": "npm run test:integration",
49
50
  "lint": "npm run lint:go && npm run lint:js",
50
51
  "lint:go": "make lint",
51
- "lint:js": "eslint -c .eslintrc.js --ext .ts ./{srpc,echo}/**/*.ts",
52
+ "lint:js": "eslint -c .eslintrc.js --ext .ts ./{srpc,echo,rpcstream}/**/*.ts",
52
53
  "prepare": "patch-package",
53
54
  "precommit": "npm run format"
54
55
  },
@@ -46,8 +46,8 @@ export class BroadcastChannelIterable<T> implements Duplex<T> {
46
46
  queue.push(ev.data)
47
47
  }
48
48
  }
49
- this.readChannel.addEventListener('message', messageListener)
50
49
 
50
+ this.readChannel.addEventListener('message', messageListener)
51
51
  return () => {
52
52
  this.readChannel.removeEventListener('message', messageListener)
53
53
  }
@@ -1,4 +1,4 @@
1
- import type { CallStart } from './rpcproto.js'
1
+ import type { CallStart } from './rpcproto.pb.js'
2
2
  import { CommonRPC } from './common-rpc.js'
3
3
 
4
4
  // ClientRPC is an ongoing RPC from the client side.
package/srpc/client.go CHANGED
@@ -19,7 +19,7 @@ type Client interface {
19
19
 
20
20
  // OpenStreamFunc opens a stream with a remote.
21
21
  // msgHandler must not be called concurrently.
22
- type OpenStreamFunc = func(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error)
22
+ type OpenStreamFunc = func(ctx context.Context, msgHandler PacketHandler) (Writer, error)
23
23
 
24
24
  // client implements Client with a transport.
25
25
  type client struct {
@@ -89,7 +89,7 @@ func (c *client) NewStream(ctx context.Context, service, method string, firstMsg
89
89
  return nil, err
90
90
  }
91
91
 
92
- return NewRPCStream(ctx, clientRPC.writer, clientRPC.dataCh), nil
92
+ return NewMsgStream(ctx, clientRPC.writer, clientRPC.dataCh), nil
93
93
  }
94
94
 
95
95
  // _ is a type assertion
package/srpc/client.ts CHANGED
@@ -29,36 +29,38 @@ function writeClientStream(call: ClientRPC, data: Observable<Uint8Array>) {
29
29
 
30
30
  // Client implements the ts-proto Rpc interface with the drpcproto protocol.
31
31
  export class Client implements TsProtoRpc {
32
- // openConnFn is a promise which contains the OpenStreamFunc.
33
- private openConnFn: Promise<OpenStreamFunc>
34
- // _openConnFn resolves openConnFn.
35
- private _openConnFn?: (conn?: OpenStreamFunc, err?: Error) => void
32
+ // openStreamFn is a promise which contains the OpenStreamFunc.
33
+ private openStreamFn: Promise<OpenStreamFunc>
34
+ // _openStreamFn resolves openStreamFn.
35
+ private _openStreamFn?: (conn?: OpenStreamFunc, err?: Error) => void
36
36
 
37
- constructor(openConnFn?: OpenStreamFunc) {
38
- this.openConnFn = this.setOpenConnFn(openConnFn)
37
+ constructor(openStreamFn?: OpenStreamFunc) {
38
+ this.openStreamFn = this.setOpenStreamFn(openStreamFn)
39
39
  }
40
40
 
41
- // setOpenConnFn updates the openConnFn for the Client.
42
- public setOpenConnFn(openConnFn?: OpenStreamFunc): Promise<OpenStreamFunc> {
43
- if (this._openConnFn) {
44
- if (openConnFn) {
45
- this._openConnFn(openConnFn)
46
- this._openConnFn = undefined
41
+ // setOpenStreamFn updates the openStreamFn for the Client.
42
+ public setOpenStreamFn(
43
+ openStreamFn?: OpenStreamFunc
44
+ ): Promise<OpenStreamFunc> {
45
+ if (this._openStreamFn) {
46
+ if (openStreamFn) {
47
+ this._openStreamFn(openStreamFn)
48
+ this._openStreamFn = undefined
47
49
  }
48
50
  } else {
49
- if (openConnFn) {
50
- this.openConnFn = Promise.resolve(openConnFn)
51
+ if (openStreamFn) {
52
+ this.openStreamFn = Promise.resolve(openStreamFn)
51
53
  } else {
52
- this.initOpenConnFn()
54
+ this.initOpenStreamFn()
53
55
  }
54
56
  }
55
- return this.openConnFn
57
+ return this.openStreamFn
56
58
  }
57
59
 
58
- // initOpenConnFn creates the empty Promise for openConnFn.
59
- private initOpenConnFn(): Promise<OpenStreamFunc> {
60
+ // initOpenStreamFn creates the empty Promise for openStreamFn.
61
+ private initOpenStreamFn(): Promise<OpenStreamFunc> {
60
62
  const openPromise = new Promise<OpenStreamFunc>((resolve, reject) => {
61
- this._openConnFn = (conn?: OpenStreamFunc, err?: Error) => {
63
+ this._openStreamFn = (conn?: OpenStreamFunc, err?: Error) => {
62
64
  if (err) {
63
65
  reject(err)
64
66
  } else if (conn) {
@@ -66,8 +68,8 @@ export class Client implements TsProtoRpc {
66
68
  }
67
69
  }
68
70
  })
69
- this.openConnFn = openPromise
70
- return this.openConnFn
71
+ this.openStreamFn = openPromise
72
+ return this.openStreamFn
71
73
  }
72
74
 
73
75
  // request starts a non-streaming request.
@@ -168,8 +170,8 @@ export class Client implements TsProtoRpc {
168
170
  rpcMethod: string,
169
171
  data: Uint8Array | null
170
172
  ): Promise<ClientRPC> {
171
- const openConnFn = await this.openConnFn
172
- const conn = await openConnFn()
173
+ const openStreamFn = await this.openStreamFn
174
+ const conn = await openStreamFn()
173
175
  const call = new ClientRPC(rpcService, rpcMethod)
174
176
  pipe(
175
177
  conn,
@@ -1,8 +1,8 @@
1
1
  import type { Source, Sink } from 'it-stream-types'
2
2
  import { pushable } from 'it-pushable'
3
3
 
4
- import type { CallData, CallStart } from './rpcproto.js'
5
- import { Packet } from './rpcproto.js'
4
+ import type { CallData, CallStart } from './rpcproto.pb.js'
5
+ import { Packet } from './rpcproto.pb.js'
6
6
 
7
7
  // CommonRPC is common logic between server and client RPCs.
8
8
  export class CommonRPC {
package/srpc/conn.ts CHANGED
@@ -19,7 +19,7 @@ export interface ConnParams {
19
19
  // Implemented by Server.
20
20
  export interface StreamHandler {
21
21
  // handleStream handles an incoming stream.
22
- handleStream(strm: Duplex<Uint8Array>): Promise<void>
22
+ handleStream(strm: Duplex<Uint8Array>): void
23
23
  }
24
24
 
25
25
  // Conn implements a generic connection with a two-way stream.
package/srpc/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { OpenStreamFunc } from './stream.js'
1
+ export type { PacketHandler, Stream, OpenStreamFunc } from './stream.js'
2
2
  export { Client } from './client.js'
3
3
  export { Server } from './server.js'
4
4
  export { Conn, ConnParams } from './conn.js'
@@ -9,9 +9,9 @@ export {
9
9
  newBroadcastChannelIterable,
10
10
  BroadcastChannelConn,
11
11
  } from './broadcast-channel.js'
12
-
13
12
  export {
14
13
  MessagePortIterable,
15
14
  newMessagePortIterable,
16
15
  MessagePortConn,
17
16
  } from './message-port.js'
17
+ export { ObservableSource } from './observable-source.js'
@@ -5,8 +5,8 @@ import (
5
5
  "io"
6
6
  )
7
7
 
8
- // RPCStream implements the stream interface passed to implementations.
9
- type RPCStream struct {
8
+ // MsgStream implements the stream interface passed to implementations.
9
+ type MsgStream struct {
10
10
  // ctx is the stream context
11
11
  ctx context.Context
12
12
  // writer is the stream writer
@@ -15,10 +15,10 @@ type RPCStream struct {
15
15
  dataCh chan []byte
16
16
  }
17
17
 
18
- // NewRPCStream constructs a new Stream with a ClientRPC.
18
+ // NewMsgStream constructs a new Stream with a ClientRPC.
19
19
  // dataCh should be closed when no more messages will arrive.
20
- func NewRPCStream(ctx context.Context, writer Writer, dataCh chan []byte) *RPCStream {
21
- return &RPCStream{
20
+ func NewMsgStream(ctx context.Context, writer Writer, dataCh chan []byte) *MsgStream {
21
+ return &MsgStream{
22
22
  ctx: ctx,
23
23
  writer: writer,
24
24
  dataCh: dataCh,
@@ -26,12 +26,12 @@ func NewRPCStream(ctx context.Context, writer Writer, dataCh chan []byte) *RPCSt
26
26
  }
27
27
 
28
28
  // Context is canceled when the Stream is no longer valid.
29
- func (r *RPCStream) Context() context.Context {
29
+ func (r *MsgStream) Context() context.Context {
30
30
  return r.ctx
31
31
  }
32
32
 
33
33
  // MsgSend sends the message to the remote.
34
- func (r *RPCStream) MsgSend(msg Message) error {
34
+ func (r *MsgStream) MsgSend(msg Message) error {
35
35
  select {
36
36
  case <-r.ctx.Done():
37
37
  return context.Canceled
@@ -48,7 +48,7 @@ func (r *RPCStream) MsgSend(msg Message) error {
48
48
 
49
49
  // MsgRecv receives an incoming message from the remote.
50
50
  // Parses the message into the object at msg.
51
- func (r *RPCStream) MsgRecv(msg Message) error {
51
+ func (r *MsgStream) MsgRecv(msg Message) error {
52
52
  select {
53
53
  case <-r.Context().Done():
54
54
  return context.Canceled
@@ -61,16 +61,16 @@ func (r *RPCStream) MsgRecv(msg Message) error {
61
61
  }
62
62
 
63
63
  // CloseSend signals to the remote that we will no longer send any messages.
64
- func (r *RPCStream) CloseSend() error {
64
+ func (r *MsgStream) CloseSend() error {
65
65
  outPkt := NewCallDataPacket(nil, false, true, nil)
66
66
  return r.writer.WritePacket(outPkt)
67
67
  }
68
68
 
69
69
  // Close closes the stream.
70
- func (r *RPCStream) Close() error {
70
+ func (r *MsgStream) Close() error {
71
71
  _ = r.writer.Close()
72
72
  return nil
73
73
  }
74
74
 
75
75
  // _ is a type assertion
76
- var _ Stream = ((*RPCStream)(nil))
76
+ var _ Stream = ((*MsgStream)(nil))
@@ -14,7 +14,7 @@ func NewClientWithMuxedConn(conn network.MuxedConn) Client {
14
14
 
15
15
  // NewOpenStreamWithMuxedConn constructs a OpenStream func with a MuxedConn.
16
16
  func NewOpenStreamWithMuxedConn(conn network.MuxedConn) OpenStreamFunc {
17
- return func(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error) {
17
+ return func(ctx context.Context, msgHandler PacketHandler) (Writer, error) {
18
18
  mstrm, err := conn.OpenStream(ctx)
19
19
  if err != nil {
20
20
  return nil, err
@@ -0,0 +1,40 @@
1
+ import { Source } from 'it-stream-types'
2
+ import { pushable, Pushable } from 'it-pushable'
3
+ import { Observable, Subscription } from 'rxjs'
4
+
5
+ // ObservableSource wraps an Observable into a Source.
6
+ export class ObservableSource<T> {
7
+ // source is the source for observable objects.
8
+ public readonly source: Source<T>
9
+ // _source emits incoming data to the source.
10
+ private readonly _source: {
11
+ push: (val: T) => void
12
+ end: (err?: Error) => void
13
+ }
14
+ // subscription is the observable subscription
15
+ private readonly subscription: Subscription
16
+
17
+ constructor(observable: Observable<T>) {
18
+ const source: Pushable<T> = pushable({ objectMode: true })
19
+ this.source = source
20
+ this._source = source
21
+
22
+ this.subscription = observable.subscribe({
23
+ next: (value: T) => {
24
+ this._source.push(value)
25
+ },
26
+ error: (err) => {
27
+ this._source.end(err)
28
+ },
29
+ complete: () => {
30
+ this._source.end()
31
+ },
32
+ })
33
+ }
34
+
35
+ // close closes the subscription.
36
+ public close(err?: Error) {
37
+ this._source.end(err)
38
+ this.subscription.unsubscribe()
39
+ }
40
+ }
package/srpc/packet.ts CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  decode as lengthPrefixDecode,
5
5
  } from 'it-length-prefixed'
6
6
 
7
- import { Packet } from './rpcproto.js'
7
+ import { Packet } from './rpcproto.pb.js'
8
8
  import {
9
9
  buildDecodeMessageTransform,
10
10
  buildEncodeMessageTransform,
File without changes
@@ -9,7 +9,7 @@ import (
9
9
  // Stream with the given Server. Starts read pumps for both. Starts the
10
10
  // HandleStream function on the server in a separate goroutine.
11
11
  func NewServerPipe(server *Server) OpenStreamFunc {
12
- return func(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error) {
12
+ return func(ctx context.Context, msgHandler PacketHandler) (Writer, error) {
13
13
  srvPipe, clientPipe := net.Pipe()
14
14
  go func() {
15
15
  _ = server.HandleStream(ctx, srvPipe)
@@ -133,7 +133,7 @@ func (r *ServerRPC) HandleCallData(pkt *CallData) error {
133
133
  func (r *ServerRPC) invokeRPC() {
134
134
  // ctx := r.ctx
135
135
  serviceID, methodID := r.service, r.method
136
- strm := NewRPCStream(r.ctx, r.writer, r.dataCh)
136
+ strm := NewMsgStream(r.ctx, r.writer, r.dataCh)
137
137
  ok, err := r.mux.InvokeMethod(serviceID, methodID, strm)
138
138
  if err == nil && !ok {
139
139
  err = ErrUnimplemented
@@ -1,6 +1,6 @@
1
1
  import type { Sink } from 'it-stream-types'
2
2
 
3
- import type { CallData, CallStart } from './rpcproto.js'
3
+ import type { CallData, CallStart } from './rpcproto.pb.js'
4
4
  import { CommonRPC } from './common-rpc.js'
5
5
  import { InvokeFn } from './handler.js'
6
6
  import { Mux } from './mux.js'
package/srpc/server.go CHANGED
@@ -20,6 +20,11 @@ func NewServer(mux Mux) *Server {
20
20
  }
21
21
  }
22
22
 
23
+ // GetMux returns the mux.
24
+ func (s *Server) GetMux() Mux {
25
+ return s.mux
26
+ }
27
+
23
28
  // HandleStream handles an incoming ReadWriteCloser stream.
24
29
  func (s *Server) HandleStream(ctx context.Context, rwc io.ReadWriteCloser) error {
25
30
  subCtx, subCtxCancel := context.WithCancel(ctx)
package/srpc/server.ts CHANGED
@@ -4,7 +4,7 @@ import { pipe } from 'it-pipe'
4
4
 
5
5
  import { Mux } from './mux.js'
6
6
  import { ServerRPC } from './server-rpc.js'
7
- import { Packet } from './rpcproto.js'
7
+ import { Packet } from './rpcproto.pb.js'
8
8
  import {
9
9
  parseLengthPrefixTransform,
10
10
  prependLengthPrefixTransform,
@@ -29,15 +29,14 @@ export class Server implements StreamHandler {
29
29
  }
30
30
 
31
31
  // handleStream handles an incoming Uint8Array message duplex.
32
- // closes the stream when the rpc completes.
33
- public handleStream(stream: Stream): Promise<void> {
32
+ public handleStream(stream: Stream): ServerRPC {
34
33
  return this.handleDuplex(stream)
35
34
  }
36
35
 
37
36
  // handleDuplex handles an incoming message duplex.
38
- public async handleDuplex(stream: Duplex<Uint8Array>): Promise<void> {
37
+ public handleDuplex(stream: Duplex<Uint8Array>): ServerRPC {
39
38
  const rpc = this.startRpc()
40
- await pipe(
39
+ pipe(
41
40
  stream,
42
41
  parseLengthPrefixTransform(),
43
42
  decodePacketSource,
@@ -46,11 +45,13 @@ export class Server implements StreamHandler {
46
45
  prependLengthPrefixTransform(),
47
46
  stream
48
47
  )
48
+ return rpc
49
49
  }
50
50
 
51
51
  // handlePacketStream handles an incoming Packet duplex.
52
- public async handlePacketStream(stream: Duplex<Packet>): Promise<void> {
52
+ public handlePacketStream(stream: Duplex<Packet>): ServerRPC {
53
53
  const rpc = this.startRpc()
54
- await pipe(stream, rpc, stream)
54
+ pipe(stream, rpc, stream)
55
+ return rpc
55
56
  }
56
57
  }
package/srpc/stream.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Packet } from './rpcproto'
1
+ import type { Packet } from './rpcproto.pb.js'
2
2
  import type { Duplex } from 'it-stream-types'
3
3
 
4
4
  // PacketHandler handles incoming packets.
package/srpc/websocket.go CHANGED
@@ -43,7 +43,7 @@ func (w *WebSocketConn) AcceptStream() (io.ReadWriteCloser, error) {
43
43
  }
44
44
 
45
45
  // OpenStream tries to open a stream with the remote.
46
- func (w *WebSocketConn) OpenStream(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error) {
46
+ func (w *WebSocketConn) OpenStream(ctx context.Context, msgHandler PacketHandler) (Writer, error) {
47
47
  muxedStream, err := w.mconn.OpenStream(ctx)
48
48
  if err != nil {
49
49
  return nil, err
package/e2e/debug.test DELETED
Binary file