@@ -15,6 +15,7 @@ import type {
1515import type { ReadableWritablePair } from 'stream/web' ;
1616import type { JSONValue } from '../types' ;
1717import type { MiddlewareFactory } from './types' ;
18+ import { TransformStream } from 'stream/web' ;
1819import { ReadableStream } from 'stream/web' ;
1920import { CreateDestroy , ready } from '@matrixai/async-init/dist/CreateDestroy' ;
2021import Logger from '@matrixai/logger' ;
@@ -191,14 +192,24 @@ class RPCServer extends EventTarget {
191192 O extends JSONValue ,
192193 > ( method : string , handler : DuplexHandlerImplementation < I , O > ) : void {
193194 const rawSteamHandler : RawHandlerImplementation = (
194- [ input , header ] ,
195+ [ header , input ] ,
195196 connectionInfo ,
196197 ctx ,
197198 ) => {
198199 // Setting up middleware
199- const middleware = this . middlewareFactory ( header ) ;
200+ const middleware = this . middlewareFactory ( ) ;
200201 // Forward from the client to the server
201- const forwardStream = input . pipeThrough ( middleware . forward ) ;
202+ const headerStream = new TransformStream ( {
203+ start ( controller ) {
204+ controller . enqueue ( Buffer . from ( JSON . stringify ( header ) ) ) ;
205+ } ,
206+ transform ( chunk , controller ) {
207+ controller . enqueue ( chunk ) ;
208+ } ,
209+ } ) ;
210+ const forwardStream = input
211+ . pipeThrough ( headerStream )
212+ . pipeThrough ( middleware . forward ) ;
202213 // Reverse from the server to the client
203214 const reverseStream = middleware . reverse . writable ;
204215 // Generator derived from handler
@@ -210,17 +221,22 @@ class RPCServer extends EventTarget {
210221 yield data . params as I ;
211222 }
212223 } ;
213- for await ( const response of handler ( inputGen ( ) , connectionInfo , ctx ) ) {
224+ const handlerG = handler ( inputGen ( ) , connectionInfo , ctx ) ;
225+ for await ( const response of handlerG ) {
214226 const responseMessage : JSONRPCResponseResult = {
215227 jsonrpc : '2.0' ,
216228 result : response ,
217229 id : null ,
218230 } ;
219- yield responseMessage ;
231+ try {
232+ yield responseMessage ;
233+ } catch ( e ) {
234+ // This catches any exceptions thrown into the reverse stream
235+ await handlerG . throw ( e ) ;
236+ }
220237 }
221238 } ;
222239 const outputGenerator = outputGen ( ) ;
223- let reason : any | undefined = undefined ;
224240 const reverseMiddlewareStream = new ReadableStream < JSONRPCResponse > ( {
225241 pull : async ( controller ) => {
226242 try {
@@ -231,39 +247,46 @@ class RPCServer extends EventTarget {
231247 }
232248 controller . enqueue ( value ) ;
233249 } catch ( e ) {
234- if ( reason == null ) {
235- // We want to convert this error to an error message and pass it along
236- const rpcError : JSONRPCError = {
237- code : e . exitCode ?? sysexits . UNKNOWN ,
238- message : e . description ?? '' ,
239- data : rpcUtils . fromError ( e , this . sensitive ) ,
240- } ;
241- const rpcErrorMessage : JSONRPCResponseError = {
242- jsonrpc : '2.0' ,
243- error : rpcError ,
244- id : null ,
245- } ;
246- controller . enqueue ( rpcErrorMessage ) ;
247- } else {
248- // These errors are emitted to the event system
249- // This contains the original error from enqueuing
250- this . dispatchEvent (
251- new rpcEvents . RPCErrorEvent ( {
252- detail : new rpcErrors . ErrorRPCSendErrorFailed ( undefined , {
253- cause : [ e , reason ] ,
254- } ) ,
255- } ) ,
256- ) ;
257- }
250+ const rpcError : JSONRPCError = {
251+ code : e . exitCode ?? sysexits . UNKNOWN ,
252+ message : e . description ?? '' ,
253+ data : rpcUtils . fromError ( e , this . sensitive ) ,
254+ } ;
255+ const rpcErrorMessage : JSONRPCResponseError = {
256+ jsonrpc : '2.0' ,
257+ error : rpcError ,
258+ id : null ,
259+ } ;
260+ controller . enqueue ( rpcErrorMessage ) ;
258261 await forwardStream . cancel (
259262 new rpcErrors . ErrorRPCHandlerFailed ( 'Error clean up' ) ,
260263 ) ;
261264 controller . close ( ) ;
262265 }
263266 } ,
264- cancel : async ( _reason ) => {
265- reason = _reason ;
266- await outputGenerator . throw ( _reason ) ;
267+ cancel : async ( reason ) => {
268+ try {
269+ // Throw the reason into the reverse stream
270+ await outputGenerator . throw ( reason ) ;
271+ } catch ( e ) {
272+ // If the e is the same as the reason
273+ // then the handler did not care about the reason
274+ // and we just discard it
275+ if ( e !== reason ) {
276+ this . dispatchEvent (
277+ new rpcEvents . RPCErrorEvent ( {
278+ detail : new rpcErrors . ErrorRPCSendErrorFailed (
279+ 'Stream has been cancelled' ,
280+ {
281+ cause : e ,
282+ }
283+ ) ,
284+ } ) ,
285+ ) ;
286+ }
287+ }
288+ // await outputGenerator.nexj
289+ // handlerAbortController.abort(reason);
267290 } ,
268291 } ) ;
269292 void reverseMiddlewareStream . pipeTo ( reverseStream ) . catch ( ( ) => { } ) ;
@@ -281,6 +304,9 @@ class RPCServer extends EventTarget {
281304 connectionInfo ,
282305 ctx ,
283306 ) {
307+ // The `input` is expected to be an async iterable with only 1 value.
308+ // Unlike generators, there is no `next()` method.
309+ // So we use `break` after the first iteration.
284310 for await ( const inputVal of input ) {
285311 yield await handler ( inputVal , connectionInfo , ctx ) ;
286312 break ;
@@ -369,7 +395,7 @@ class RPCServer extends EventTarget {
369395 return ;
370396 }
371397 const outputStream = handler (
372- [ inputStream , leadingMetadataMessage ] ,
398+ [ leadingMetadataMessage , inputStream ] ,
373399 connectionInfo ,
374400 { signal : abortController . signal } ,
375401 ) ;
0 commit comments