starpc 0.4.9 → 0.5.0

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 (64) hide show
  1. package/Makefile +1 -0
  2. package/README.md +20 -10
  3. package/dist/echo/client-test.d.ts +1 -0
  4. package/dist/echo/client-test.js +20 -18
  5. package/dist/echo/echo.pb.d.ts +165 -12
  6. package/dist/echo/echo.pb.js +61 -17
  7. package/dist/echo/server.d.ts +8 -4
  8. package/dist/echo/server.js +29 -37
  9. package/dist/rpcstream/rpcstream.d.ts +6 -6
  10. package/dist/rpcstream/rpcstream.js +92 -51
  11. package/dist/rpcstream/rpcstream.pb.d.ts +46 -1
  12. package/dist/rpcstream/rpcstream.pb.js +157 -9
  13. package/dist/srpc/client.d.ts +3 -4
  14. package/dist/srpc/client.js +12 -46
  15. package/dist/srpc/common-rpc.d.ts +3 -2
  16. package/dist/srpc/common-rpc.js +12 -0
  17. package/dist/srpc/definition.d.ts +3 -3
  18. package/dist/srpc/handler.d.ts +2 -3
  19. package/dist/srpc/handler.js +5 -22
  20. package/dist/srpc/index.d.ts +1 -1
  21. package/dist/srpc/index.js +1 -1
  22. package/dist/srpc/packet.js +0 -32
  23. package/dist/srpc/pushable.d.ts +2 -0
  24. package/dist/srpc/pushable.js +13 -0
  25. package/dist/srpc/rpcproto.pb.d.ts +13 -6
  26. package/dist/srpc/rpcproto.pb.js +95 -10
  27. package/dist/srpc/server.d.ts +1 -0
  28. package/dist/srpc/server.js +7 -0
  29. package/dist/srpc/ts-proto-rpc.d.ts +3 -4
  30. package/e2e/e2e.ts +4 -3
  31. package/e2e/e2e_test.go +24 -1
  32. package/echo/client-test.ts +23 -18
  33. package/echo/echo.pb.go +33 -20
  34. package/echo/echo.pb.ts +90 -34
  35. package/echo/echo.proto +4 -0
  36. package/echo/echo_srpc.pb.go +77 -0
  37. package/echo/server.go +18 -0
  38. package/echo/server.ts +47 -41
  39. package/integration/integration.go +1 -2
  40. package/integration/integration.ts +5 -1
  41. package/integration/integration_srpc.pb.go +139 -0
  42. package/package.json +5 -3
  43. package/patches/ts-proto+1.115.5.patch +1339 -0
  44. package/srpc/client.ts +16 -50
  45. package/srpc/common-rpc.ts +14 -2
  46. package/srpc/definition.ts +3 -3
  47. package/srpc/handler.ts +17 -34
  48. package/srpc/index.ts +1 -1
  49. package/srpc/muxed-conn.go +2 -2
  50. package/srpc/packet-rw.go +4 -6
  51. package/srpc/packet.ts +0 -33
  52. package/srpc/pushable.ts +17 -0
  53. package/srpc/rpcproto.pb.ts +122 -12
  54. package/srpc/server-pipe.go +2 -2
  55. package/srpc/server.go +2 -2
  56. package/srpc/server.ts +8 -0
  57. package/srpc/ts-proto-rpc.ts +4 -6
  58. package/srpc/websocket.go +2 -2
  59. package/dist/echo/sever.d.ts +0 -0
  60. package/dist/echo/sever.js +0 -1
  61. package/dist/srpc/observable-source.d.ts +0 -9
  62. package/dist/srpc/observable-source.js +0 -25
  63. package/echo/sever.ts +0 -0
  64. package/srpc/observable-source.ts +0 -40
package/echo/echo.pb.go CHANGED
@@ -10,6 +10,7 @@ import (
10
10
  reflect "reflect"
11
11
  sync "sync"
12
12
 
13
+ rpcstream "github.com/aperturerobotics/starpc/rpcstream"
13
14
  protoreflect "google.golang.org/protobuf/reflect/protoreflect"
14
15
  protoimpl "google.golang.org/protobuf/runtime/protoimpl"
15
16
  )
@@ -75,22 +76,31 @@ var file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDesc = []byte{
75
76
  0x0a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x65,
76
77
  0x72, 0x74, 0x75, 0x72, 0x65, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x69, 0x63, 0x73, 0x2f, 0x73, 0x74,
77
78
  0x61, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x70,
78
- 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x65, 0x63, 0x68, 0x6f, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x63,
79
- 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20,
80
- 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x32, 0xca, 0x01, 0x0a, 0x06, 0x45, 0x63,
81
- 0x68, 0x6f, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x0d, 0x2e, 0x65,
79
+ 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x65, 0x63, 0x68, 0x6f, 0x1a, 0x3c, 0x67, 0x69, 0x74, 0x68,
80
+ 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x65, 0x72, 0x74, 0x75, 0x72, 0x65, 0x72,
81
+ 0x6f, 0x62, 0x6f, 0x74, 0x69, 0x63, 0x73, 0x2f, 0x73, 0x74, 0x61, 0x72, 0x70, 0x63, 0x2f, 0x72,
82
+ 0x70, 0x63, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x72, 0x70, 0x63, 0x73, 0x74, 0x72, 0x65,
83
+ 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x63, 0x68, 0x6f,
84
+ 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
85
+ 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x32, 0x93, 0x02, 0x0a, 0x06, 0x45, 0x63, 0x68, 0x6f,
86
+ 0x65, 0x72, 0x12, 0x24, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x0d, 0x2e, 0x65, 0x63, 0x68,
87
+ 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f,
88
+ 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x12, 0x32, 0x0a, 0x10, 0x45, 0x63, 0x68, 0x6f,
89
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x0d, 0x2e, 0x65,
82
90
  0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63,
83
- 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x12, 0x32, 0x0a, 0x10, 0x45, 0x63,
84
- 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x0d,
85
- 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e,
86
- 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x30, 0x01, 0x12, 0x32,
87
- 0x0a, 0x10, 0x45, 0x63, 0x68, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65,
91
+ 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x10,
92
+ 0x45, 0x63, 0x68, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
93
+ 0x12, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x1a,
94
+ 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67, 0x28, 0x01,
95
+ 0x12, 0x32, 0x0a, 0x0e, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74, 0x72, 0x65,
88
96
  0x61, 0x6d, 0x12, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73,
89
97
  0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d, 0x73, 0x67,
90
- 0x28, 0x01, 0x12, 0x32, 0x0a, 0x0e, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x69, 0x64, 0x69, 0x53, 0x74,
91
- 0x72, 0x65, 0x61, 0x6d, 0x12, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f,
92
- 0x4d, 0x73, 0x67, 0x1a, 0x0d, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x63, 0x68, 0x6f, 0x4d,
93
- 0x73, 0x67, 0x28, 0x01, 0x30, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
98
+ 0x28, 0x01, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x09, 0x52, 0x70, 0x63, 0x53, 0x74, 0x72, 0x65, 0x61,
99
+ 0x6d, 0x12, 0x1a, 0x2e, 0x72, 0x70, 0x63, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x52, 0x70,
100
+ 0x63, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x1a, 0x1a, 0x2e,
101
+ 0x72, 0x70, 0x63, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x74, 0x72,
102
+ 0x65, 0x61, 0x6d, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x28, 0x01, 0x30, 0x01, 0x62, 0x06, 0x70,
103
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
94
104
  }
95
105
 
96
106
  var (
@@ -107,19 +117,22 @@ func file_github_com_aperturerobotics_starpc_echo_echo_proto_rawDescGZIP() []byt
107
117
 
108
118
  var file_github_com_aperturerobotics_starpc_echo_echo_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
109
119
  var file_github_com_aperturerobotics_starpc_echo_echo_proto_goTypes = []interface{}{
110
- (*EchoMsg)(nil), // 0: echo.EchoMsg
120
+ (*EchoMsg)(nil), // 0: echo.EchoMsg
121
+ (*rpcstream.RpcStreamPacket)(nil), // 1: rpcstream.RpcStreamPacket
111
122
  }
112
123
  var file_github_com_aperturerobotics_starpc_echo_echo_proto_depIdxs = []int32{
113
124
  0, // 0: echo.Echoer.Echo:input_type -> echo.EchoMsg
114
125
  0, // 1: echo.Echoer.EchoServerStream:input_type -> echo.EchoMsg
115
126
  0, // 2: echo.Echoer.EchoClientStream:input_type -> echo.EchoMsg
116
127
  0, // 3: echo.Echoer.EchoBidiStream:input_type -> echo.EchoMsg
117
- 0, // 4: echo.Echoer.Echo:output_type -> echo.EchoMsg
118
- 0, // 5: echo.Echoer.EchoServerStream:output_type -> echo.EchoMsg
119
- 0, // 6: echo.Echoer.EchoClientStream:output_type -> echo.EchoMsg
120
- 0, // 7: echo.Echoer.EchoBidiStream:output_type -> echo.EchoMsg
121
- 4, // [4:8] is the sub-list for method output_type
122
- 0, // [0:4] is the sub-list for method input_type
128
+ 1, // 4: echo.Echoer.RpcStream:input_type -> rpcstream.RpcStreamPacket
129
+ 0, // 5: echo.Echoer.Echo:output_type -> echo.EchoMsg
130
+ 0, // 6: echo.Echoer.EchoServerStream:output_type -> echo.EchoMsg
131
+ 0, // 7: echo.Echoer.EchoClientStream:output_type -> echo.EchoMsg
132
+ 0, // 8: echo.Echoer.EchoBidiStream:output_type -> echo.EchoMsg
133
+ 1, // 9: echo.Echoer.RpcStream:output_type -> rpcstream.RpcStreamPacket
134
+ 5, // [5:10] is the sub-list for method output_type
135
+ 0, // [0:5] is the sub-list for method input_type
123
136
  0, // [0:0] is the sub-list for extension type_name
124
137
  0, // [0:0] is the sub-list for extension extendee
125
138
  0, // [0:0] is the sub-list for field type_name
package/echo/echo.pb.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /* eslint-disable */
2
2
  import Long from 'long'
3
+ import { EchoMsg as EchoMsg1 } from './echo.pb.js'
4
+ import { RpcStreamPacket } from '../rpcstream/rpcstream.pb.js'
3
5
  import * as _m0 from 'protobufjs/minimal'
4
- import { Observable } from 'rxjs'
5
- import { map } from 'rxjs/operators'
6
6
 
7
7
  export const protobufPackage = 'echo'
8
8
 
@@ -44,6 +44,40 @@ export const EchoMsg = {
44
44
  return message
45
45
  },
46
46
 
47
+ // encodeTransform encodes a source of message objects.
48
+ // Transform<EchoMsg, Uint8Array>
49
+ async *encodeTransform(
50
+ source: AsyncIterable<EchoMsg | EchoMsg[]> | Iterable<EchoMsg | EchoMsg[]>
51
+ ): AsyncIterable<Uint8Array> {
52
+ for await (const pkt of source) {
53
+ if (Array.isArray(pkt)) {
54
+ for (const p of pkt) {
55
+ yield* [EchoMsg.encode(p).finish()]
56
+ }
57
+ } else {
58
+ yield* [EchoMsg.encode(pkt).finish()]
59
+ }
60
+ }
61
+ },
62
+
63
+ // decodeTransform decodes a source of encoded messages.
64
+ // Transform<Uint8Array, EchoMsg>
65
+ async *decodeTransform(
66
+ source:
67
+ | AsyncIterable<Uint8Array | Uint8Array[]>
68
+ | Iterable<Uint8Array | Uint8Array[]>
69
+ ): AsyncIterable<EchoMsg> {
70
+ for await (const pkt of source) {
71
+ if (Array.isArray(pkt)) {
72
+ for (const p of pkt) {
73
+ yield* [EchoMsg.decode(p)]
74
+ }
75
+ } else {
76
+ yield* [EchoMsg.decode(pkt)]
77
+ }
78
+ }
79
+ },
80
+
47
81
  fromJSON(object: any): EchoMsg {
48
82
  return {
49
83
  body: isSet(object.body) ? String(object.body) : '',
@@ -66,13 +100,17 @@ export const EchoMsg = {
66
100
  /** Echoer service returns the given message. */
67
101
  export interface Echoer {
68
102
  /** Echo returns the given message. */
69
- Echo(request: EchoMsg): Promise<EchoMsg>
103
+ Echo(request: EchoMsg1): Promise<EchoMsg1>
70
104
  /** EchoServerStream is an example of a server -> client one-way stream. */
71
- EchoServerStream(request: EchoMsg): Observable<EchoMsg>
105
+ EchoServerStream(request: EchoMsg1): AsyncIterable<EchoMsg1>
72
106
  /** EchoClientStream is an example of client->server one-way stream. */
73
- EchoClientStream(request: Observable<EchoMsg>): Promise<EchoMsg>
107
+ EchoClientStream(request: AsyncIterable<EchoMsg1>): Promise<EchoMsg1>
74
108
  /** EchoBidiStream is an example of a two-way stream. */
75
- EchoBidiStream(request: Observable<EchoMsg>): Observable<EchoMsg>
109
+ EchoBidiStream(request: AsyncIterable<EchoMsg1>): AsyncIterable<EchoMsg1>
110
+ /** RpcStream opens a nested rpc call stream. */
111
+ RpcStream(
112
+ request: AsyncIterable<RpcStreamPacket>
113
+ ): AsyncIterable<RpcStreamPacket>
76
114
  }
77
115
 
78
116
  export class EchoerClientImpl implements Echoer {
@@ -83,45 +121,54 @@ export class EchoerClientImpl implements Echoer {
83
121
  this.EchoServerStream = this.EchoServerStream.bind(this)
84
122
  this.EchoClientStream = this.EchoClientStream.bind(this)
85
123
  this.EchoBidiStream = this.EchoBidiStream.bind(this)
124
+ this.RpcStream = this.RpcStream.bind(this)
86
125
  }
87
- Echo(request: EchoMsg): Promise<EchoMsg> {
88
- const data = EchoMsg.encode(request).finish()
126
+ Echo(request: EchoMsg1): Promise<EchoMsg1> {
127
+ const data = EchoMsg1.encode(request).finish()
89
128
  const promise = this.rpc.request('echo.Echoer', 'Echo', data)
90
- return promise.then((data) => EchoMsg.decode(new _m0.Reader(data)))
129
+ return promise.then((data) => EchoMsg1.decode(new _m0.Reader(data)))
91
130
  }
92
131
 
93
- EchoServerStream(request: EchoMsg): Observable<EchoMsg> {
94
- const data = EchoMsg.encode(request).finish()
132
+ EchoServerStream(request: EchoMsg1): AsyncIterable<EchoMsg1> {
133
+ const data = EchoMsg1.encode(request).finish()
95
134
  const result = this.rpc.serverStreamingRequest(
96
135
  'echo.Echoer',
97
136
  'EchoServerStream',
98
137
  data
99
138
  )
100
- return result.pipe(map((data) => EchoMsg.decode(new _m0.Reader(data))))
139
+ return EchoMsg1.decodeTransform(result)
101
140
  }
102
141
 
103
- EchoClientStream(request: Observable<EchoMsg>): Promise<EchoMsg> {
104
- const data = request.pipe(
105
- map((request) => EchoMsg.encode(request).finish())
106
- )
142
+ EchoClientStream(request: AsyncIterable<EchoMsg1>): Promise<EchoMsg1> {
143
+ const data = EchoMsg1.encodeTransform(request)
107
144
  const promise = this.rpc.clientStreamingRequest(
108
145
  'echo.Echoer',
109
146
  'EchoClientStream',
110
147
  data
111
148
  )
112
- return promise.then((data) => EchoMsg.decode(new _m0.Reader(data)))
149
+ return promise.then((data) => EchoMsg1.decode(new _m0.Reader(data)))
113
150
  }
114
151
 
115
- EchoBidiStream(request: Observable<EchoMsg>): Observable<EchoMsg> {
116
- const data = request.pipe(
117
- map((request) => EchoMsg.encode(request).finish())
118
- )
152
+ EchoBidiStream(request: AsyncIterable<EchoMsg1>): AsyncIterable<EchoMsg1> {
153
+ const data = EchoMsg1.encodeTransform(request)
119
154
  const result = this.rpc.bidirectionalStreamingRequest(
120
155
  'echo.Echoer',
121
156
  'EchoBidiStream',
122
157
  data
123
158
  )
124
- return result.pipe(map((data) => EchoMsg.decode(new _m0.Reader(data))))
159
+ return EchoMsg1.decodeTransform(result)
160
+ }
161
+
162
+ RpcStream(
163
+ request: AsyncIterable<RpcStreamPacket>
164
+ ): AsyncIterable<RpcStreamPacket> {
165
+ const data = RpcStreamPacket.encodeTransform(request)
166
+ const result = this.rpc.bidirectionalStreamingRequest(
167
+ 'echo.Echoer',
168
+ 'RpcStream',
169
+ data
170
+ )
171
+ return RpcStreamPacket.decodeTransform(result)
125
172
  }
126
173
  }
127
174
 
@@ -134,36 +181,45 @@ export const EchoerDefinition = {
134
181
  /** Echo returns the given message. */
135
182
  echo: {
136
183
  name: 'Echo',
137
- requestType: EchoMsg,
184
+ requestType: EchoMsg1,
138
185
  requestStream: false,
139
- responseType: EchoMsg,
186
+ responseType: EchoMsg1,
140
187
  responseStream: false,
141
188
  options: {},
142
189
  },
143
190
  /** EchoServerStream is an example of a server -> client one-way stream. */
144
191
  echoServerStream: {
145
192
  name: 'EchoServerStream',
146
- requestType: EchoMsg,
193
+ requestType: EchoMsg1,
147
194
  requestStream: false,
148
- responseType: EchoMsg,
195
+ responseType: EchoMsg1,
149
196
  responseStream: true,
150
197
  options: {},
151
198
  },
152
199
  /** EchoClientStream is an example of client->server one-way stream. */
153
200
  echoClientStream: {
154
201
  name: 'EchoClientStream',
155
- requestType: EchoMsg,
202
+ requestType: EchoMsg1,
156
203
  requestStream: true,
157
- responseType: EchoMsg,
204
+ responseType: EchoMsg1,
158
205
  responseStream: false,
159
206
  options: {},
160
207
  },
161
208
  /** EchoBidiStream is an example of a two-way stream. */
162
209
  echoBidiStream: {
163
210
  name: 'EchoBidiStream',
164
- requestType: EchoMsg,
211
+ requestType: EchoMsg1,
212
+ requestStream: true,
213
+ responseType: EchoMsg1,
214
+ responseStream: true,
215
+ options: {},
216
+ },
217
+ /** RpcStream opens a nested rpc call stream. */
218
+ rpcStream: {
219
+ name: 'RpcStream',
220
+ requestType: RpcStreamPacket,
165
221
  requestStream: true,
166
- responseType: EchoMsg,
222
+ responseType: RpcStreamPacket,
167
223
  responseStream: true,
168
224
  options: {},
169
225
  },
@@ -179,18 +235,18 @@ interface Rpc {
179
235
  clientStreamingRequest(
180
236
  service: string,
181
237
  method: string,
182
- data: Observable<Uint8Array>
238
+ data: AsyncIterable<Uint8Array>
183
239
  ): Promise<Uint8Array>
184
240
  serverStreamingRequest(
185
241
  service: string,
186
242
  method: string,
187
243
  data: Uint8Array
188
- ): Observable<Uint8Array>
244
+ ): AsyncIterable<Uint8Array>
189
245
  bidirectionalStreamingRequest(
190
246
  service: string,
191
247
  method: string,
192
- data: Observable<Uint8Array>
193
- ): Observable<Uint8Array>
248
+ data: AsyncIterable<Uint8Array>
249
+ ): AsyncIterable<Uint8Array>
194
250
  }
195
251
 
196
252
  type Builtin =
package/echo/echo.proto CHANGED
@@ -1,6 +1,8 @@
1
1
  syntax = "proto3";
2
2
  package echo;
3
3
 
4
+ import "github.com/aperturerobotics/starpc/rpcstream/rpcstream.proto";
5
+
4
6
  // Echoer service returns the given message.
5
7
  service Echoer {
6
8
  // Echo returns the given message.
@@ -11,6 +13,8 @@ service Echoer {
11
13
  rpc EchoClientStream(stream EchoMsg) returns (EchoMsg);
12
14
  // EchoBidiStream is an example of a two-way stream.
13
15
  rpc EchoBidiStream(stream EchoMsg) returns (stream EchoMsg);
16
+ // RpcStream opens a nested rpc call stream.
17
+ rpc RpcStream(stream .rpcstream.RpcStreamPacket) returns (stream .rpcstream.RpcStreamPacket);
14
18
  }
15
19
 
16
20
  // EchoMsg is the message body for Echo.
@@ -7,6 +7,7 @@ package echo
7
7
  import (
8
8
  context "context"
9
9
 
10
+ rpcstream "github.com/aperturerobotics/starpc/rpcstream"
10
11
  srpc "github.com/aperturerobotics/starpc/srpc"
11
12
  )
12
13
 
@@ -17,6 +18,7 @@ type SRPCEchoerClient interface {
17
18
  EchoServerStream(ctx context.Context, in *EchoMsg) (SRPCEchoer_EchoServerStreamClient, error)
18
19
  EchoClientStream(ctx context.Context) (SRPCEchoer_EchoClientStreamClient, error)
19
20
  EchoBidiStream(ctx context.Context) (SRPCEchoer_EchoBidiStreamClient, error)
21
+ RpcStream(ctx context.Context) (SRPCEchoer_RpcStreamClient, error)
20
22
  }
21
23
 
22
24
  type srpcEchoerClient struct {
@@ -149,11 +151,48 @@ func (x *srpcEchoer_EchoBidiStreamClient) RecvTo(m *EchoMsg) error {
149
151
  return x.MsgRecv(m)
150
152
  }
151
153
 
154
+ func (c *srpcEchoerClient) RpcStream(ctx context.Context) (SRPCEchoer_RpcStreamClient, error) {
155
+ stream, err := c.cc.NewStream(ctx, "echo.Echoer", "RpcStream", nil)
156
+ if err != nil {
157
+ return nil, err
158
+ }
159
+ strm := &srpcEchoer_RpcStreamClient{stream}
160
+ return strm, nil
161
+ }
162
+
163
+ type SRPCEchoer_RpcStreamClient interface {
164
+ srpc.Stream
165
+ Send(*rpcstream.RpcStreamPacket) error
166
+ Recv() (*rpcstream.RpcStreamPacket, error)
167
+ RecvTo(*rpcstream.RpcStreamPacket) error
168
+ }
169
+
170
+ type srpcEchoer_RpcStreamClient struct {
171
+ srpc.Stream
172
+ }
173
+
174
+ func (x *srpcEchoer_RpcStreamClient) Send(m *rpcstream.RpcStreamPacket) error {
175
+ return x.MsgSend(m)
176
+ }
177
+
178
+ func (x *srpcEchoer_RpcStreamClient) Recv() (*rpcstream.RpcStreamPacket, error) {
179
+ m := new(rpcstream.RpcStreamPacket)
180
+ if err := x.MsgRecv(m); err != nil {
181
+ return nil, err
182
+ }
183
+ return m, nil
184
+ }
185
+
186
+ func (x *srpcEchoer_RpcStreamClient) RecvTo(m *rpcstream.RpcStreamPacket) error {
187
+ return x.MsgRecv(m)
188
+ }
189
+
152
190
  type SRPCEchoerServer interface {
153
191
  Echo(context.Context, *EchoMsg) (*EchoMsg, error)
154
192
  EchoServerStream(*EchoMsg, SRPCEchoer_EchoServerStreamStream) error
155
193
  EchoClientStream(SRPCEchoer_EchoClientStreamStream) error
156
194
  EchoBidiStream(SRPCEchoer_EchoBidiStreamStream) error
195
+ RpcStream(SRPCEchoer_RpcStreamStream) error
157
196
  }
158
197
 
159
198
  type SRPCEchoerUnimplementedServer struct{}
@@ -174,6 +213,10 @@ func (s *SRPCEchoerUnimplementedServer) EchoBidiStream(SRPCEchoer_EchoBidiStream
174
213
  return srpc.ErrUnimplemented
175
214
  }
176
215
 
216
+ func (s *SRPCEchoerUnimplementedServer) RpcStream(SRPCEchoer_RpcStreamStream) error {
217
+ return srpc.ErrUnimplemented
218
+ }
219
+
177
220
  const SRPCEchoerServiceID = "echo.Echoer"
178
221
 
179
222
  type SRPCEchoerHandler struct {
@@ -188,6 +231,7 @@ func (SRPCEchoerHandler) GetMethodIDs() []string {
188
231
  "EchoServerStream",
189
232
  "EchoClientStream",
190
233
  "EchoBidiStream",
234
+ "RpcStream",
191
235
  }
192
236
  }
193
237
 
@@ -208,6 +252,8 @@ func (d *SRPCEchoerHandler) InvokeMethod(
208
252
  return true, d.InvokeMethod_EchoClientStream(d.impl, strm)
209
253
  case "EchoBidiStream":
210
254
  return true, d.InvokeMethod_EchoBidiStream(d.impl, strm)
255
+ case "RpcStream":
256
+ return true, d.InvokeMethod_RpcStream(d.impl, strm)
211
257
  default:
212
258
  return false, nil
213
259
  }
@@ -244,6 +290,11 @@ func (SRPCEchoerHandler) InvokeMethod_EchoBidiStream(impl SRPCEchoerServer, strm
244
290
  return impl.EchoBidiStream(clientStrm)
245
291
  }
246
292
 
293
+ func (SRPCEchoerHandler) InvokeMethod_RpcStream(impl SRPCEchoerServer, strm srpc.Stream) error {
294
+ clientStrm := &srpcEchoer_RpcStreamStream{strm}
295
+ return impl.RpcStream(clientStrm)
296
+ }
297
+
247
298
  func SRPCRegisterEchoer(mux srpc.Mux, impl SRPCEchoerServer) error {
248
299
  return mux.Register(&SRPCEchoerHandler{impl: impl})
249
300
  }
@@ -331,3 +382,29 @@ func (x *srpcEchoer_EchoBidiStreamStream) Recv() (*EchoMsg, error) {
331
382
  func (x *srpcEchoer_EchoBidiStreamStream) RecvTo(m *EchoMsg) error {
332
383
  return x.MsgRecv(m)
333
384
  }
385
+
386
+ type SRPCEchoer_RpcStreamStream interface {
387
+ srpc.Stream
388
+ Send(*rpcstream.RpcStreamPacket) error
389
+ Recv() (*rpcstream.RpcStreamPacket, error)
390
+ }
391
+
392
+ type srpcEchoer_RpcStreamStream struct {
393
+ srpc.Stream
394
+ }
395
+
396
+ func (x *srpcEchoer_RpcStreamStream) Send(m *rpcstream.RpcStreamPacket) error {
397
+ return x.MsgSend(m)
398
+ }
399
+
400
+ func (x *srpcEchoer_RpcStreamStream) Recv() (*rpcstream.RpcStreamPacket, error) {
401
+ m := new(rpcstream.RpcStreamPacket)
402
+ if err := x.MsgRecv(m); err != nil {
403
+ return nil, err
404
+ }
405
+ return m, nil
406
+ }
407
+
408
+ func (x *srpcEchoer_RpcStreamStream) RecvTo(m *rpcstream.RpcStreamPacket) error {
409
+ return x.MsgRecv(m)
410
+ }
package/echo/server.go CHANGED
@@ -6,11 +6,19 @@ import (
6
6
  "io"
7
7
  "time"
8
8
 
9
+ rpcstream "github.com/aperturerobotics/starpc/rpcstream"
10
+ srpc "github.com/aperturerobotics/starpc/srpc"
9
11
  "google.golang.org/protobuf/proto"
10
12
  )
11
13
 
12
14
  // EchoServer implements the server side of Echo.
13
15
  type EchoServer struct {
16
+ rpcStreamMux srpc.Mux
17
+ }
18
+
19
+ // NewEchoServer constructs a EchoServer with a RpcStream mux.
20
+ func NewEchoServer(rpcStreamMux srpc.Mux) *EchoServer {
21
+ return &EchoServer{rpcStreamMux: rpcStreamMux}
14
22
  }
15
23
 
16
24
  // Echo implements echo.SRPCEchoerServer
@@ -69,5 +77,15 @@ func (s *EchoServer) EchoBidiStream(strm SRPCEchoer_EchoBidiStreamStream) error
69
77
  }
70
78
  }
71
79
 
80
+ // RpcStream runs a rpc stream
81
+ func (r *EchoServer) RpcStream(stream SRPCEchoer_RpcStreamStream) error {
82
+ return rpcstream.HandleRpcStream(stream, func(ctx context.Context, componentID string) (srpc.Mux, error) {
83
+ if r.rpcStreamMux == nil {
84
+ return nil, errors.New("not implemented")
85
+ }
86
+ return r.rpcStreamMux, nil
87
+ })
88
+ }
89
+
72
90
  // _ is a type assertion
73
91
  var _ SRPCEchoerServer = ((*EchoServer)(nil))
package/echo/server.ts CHANGED
@@ -1,57 +1,63 @@
1
- import { Observable, from as observableFrom } from 'rxjs'
2
1
  import { Echoer, EchoMsg } from './echo.pb.js'
3
2
  import { pushable, Pushable } from 'it-pushable'
3
+ import first from 'it-first'
4
+ import { Server } from '../srpc/server.js'
5
+ import { writeToPushable } from '../srpc/pushable.js'
6
+ import { RpcStreamPacket } from '../rpcstream/rpcstream.pb.js'
7
+ import { handleRpcStream } from '../rpcstream/rpcstream.js'
4
8
 
5
9
  // EchoServer implements the Echoer server.
6
10
  export class EchoerServer implements Echoer {
11
+ // proxyServer is the server used for RpcStream requests.
12
+ private proxyServer?: Server
13
+
14
+ constructor(proxyServer?: Server) {
15
+ this.proxyServer = proxyServer
16
+ }
17
+
7
18
  public async Echo(request: EchoMsg): Promise<EchoMsg> {
8
19
  return request
9
20
  }
10
21
 
11
- public EchoServerStream(request: EchoMsg): Observable<EchoMsg> {
12
- // send 5 responses, with a 200ms delay for each
13
- return observableFrom(
14
- (async function* response(): AsyncIterable<EchoMsg> {
15
- for (let i = 0; i < 5; i++) {
16
- yield request
17
- await new Promise((resolve) => setTimeout(resolve, 200))
18
- }
19
- })()
20
- )
22
+ public async *EchoServerStream(request: EchoMsg): AsyncIterable<EchoMsg> {
23
+ for (let i = 0; i < 5; i++) {
24
+ yield request
25
+ await new Promise((resolve) => setTimeout(resolve, 200))
26
+ }
21
27
  }
22
28
 
23
- public EchoClientStream(request: Observable<EchoMsg>): Promise<EchoMsg> {
24
- return new Promise<EchoMsg>((resolve, reject) => {
25
- request.subscribe({
26
- next(msg) {
27
- resolve(msg)
28
- },
29
- error(err: any) {
30
- reject(err)
31
- },
32
- complete() {
33
- reject(new Error('none received'))
34
- },
35
- })
36
- })
29
+ public async EchoClientStream(
30
+ request: AsyncIterable<EchoMsg>
31
+ ): Promise<EchoMsg> {
32
+ // return the first message sent by the client.
33
+ const message = await first(request)
34
+ if (!message) {
35
+ throw new Error('received no messages')
36
+ }
37
+ return message
37
38
  }
38
39
 
39
- public EchoBidiStream(request: Observable<EchoMsg>): Observable<EchoMsg> {
40
+ public EchoBidiStream(
41
+ request: AsyncIterable<EchoMsg>
42
+ ): AsyncIterable<EchoMsg> {
40
43
  // build result observable
41
- const pushResponse: Pushable<EchoMsg> = pushable({ objectMode: true })
42
- const response = observableFrom(pushResponse)
43
- pushResponse.push({ body: 'hello from server' })
44
- request.subscribe({
45
- next(msg) {
46
- pushResponse.push(msg)
47
- },
48
- error(err) {
49
- pushResponse.throw(err)
50
- },
51
- complete() {
52
- pushResponse.end()
53
- },
54
- })
55
- return response
44
+ const result: Pushable<EchoMsg> = pushable({ objectMode: true })
45
+ result.push({ body: 'hello from server' })
46
+ writeToPushable(request, result)
47
+ return result
48
+ }
49
+
50
+ public RpcStream(
51
+ request: AsyncIterable<RpcStreamPacket>
52
+ ): AsyncIterable<RpcStreamPacket> {
53
+ return handleRpcStream(
54
+ request[Symbol.asyncIterator](),
55
+ async (_componentId: string): Promise<Server> => {
56
+ if (!this.proxyServer) {
57
+ throw new Error('rpc stream proxy server not set')
58
+ }
59
+ return this.proxyServer
60
+ }
61
+ )
56
62
  }
57
63
  }
@@ -11,8 +11,7 @@ import (
11
11
 
12
12
  func main() {
13
13
  mux := srpc.NewMux()
14
-
15
- echoServer := &echo.EchoServer{}
14
+ echoServer := echo.NewEchoServer(mux)
16
15
  if err := echo.SRPCRegisterEchoer(mux, echoServer); err != nil {
17
16
  logrus.Fatal(err.Error())
18
17
  }
@@ -1,5 +1,5 @@
1
1
  import { WebSocketConn } from '../srpc/websocket.js'
2
- import { runClientTest } from '../echo/client-test.js'
2
+ import { runClientTest, runRpcStreamTest } from '../echo/client-test.js'
3
3
  import WebSocket from 'isomorphic-ws'
4
4
 
5
5
  async function runRPC() {
@@ -9,7 +9,11 @@ async function runRPC() {
9
9
  const channel = new WebSocketConn(ws)
10
10
  const client = channel.buildClient()
11
11
 
12
+ console.log('Running client test via WebSocket..')
12
13
  await runClientTest(client)
14
+
15
+ console.log('Running RpcStream test via WebSocket..')
16
+ await runRpcStreamTest(client)
13
17
  }
14
18
 
15
19
  runRPC()