mirror of https://github.com/grpc/grpc-node.git
				
				
				
			grpc-js: add bidirectional streaming RPC support
This commit adds bidi streaming RPC support to the server.
This commit is contained in:
		
							parent
							
								
									3bebc2230a
								
							
						
					
					
						commit
						1aa11525fd
					
				|  | @ -204,13 +204,21 @@ export class ServerWritableStreamImpl<RequestType, ResponseType> extends | |||
| export class ServerDuplexStreamImpl<RequestType, ResponseType> extends Duplex | ||||
|     implements ServerDuplexStream<RequestType, ResponseType> { | ||||
|   cancelled: boolean; | ||||
|   private trailingMetadata: Metadata; | ||||
| 
 | ||||
|   constructor( | ||||
|       private call: Http2ServerCallStream<RequestType, ResponseType>, | ||||
|       public metadata: Metadata, private _serialize: Serialize<ResponseType>, | ||||
|       private _deserialize: Deserialize<RequestType>) { | ||||
|       public metadata: Metadata, public serialize: Serialize<ResponseType>, | ||||
|       public deserialize: Deserialize<RequestType>) { | ||||
|     super({objectMode: true}); | ||||
|     this.cancelled = false; | ||||
|     this.trailingMetadata = new Metadata(); | ||||
|     this.call.setupReadable(this); | ||||
| 
 | ||||
|     this.on('error', (err) => { | ||||
|       this.call.sendError(err as ServiceError); | ||||
|       this.end(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   getPeer(): string { | ||||
|  | @ -222,6 +230,14 @@ export class ServerDuplexStreamImpl<RequestType, ResponseType> extends Duplex | |||
|   } | ||||
| } | ||||
| 
 | ||||
| ServerDuplexStreamImpl.prototype._read = | ||||
|     ServerReadableStreamImpl.prototype._read; | ||||
| ServerDuplexStreamImpl.prototype._write = | ||||
|     ServerWritableStreamImpl.prototype._write; | ||||
| ServerDuplexStreamImpl.prototype._final = | ||||
|     ServerWritableStreamImpl.prototype._final; | ||||
| ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; | ||||
| 
 | ||||
| 
 | ||||
| // Unary response callback signature.
 | ||||
| export type sendUnaryData<ResponseType> = | ||||
|  |  | |||
|  | @ -355,5 +355,12 @@ function handleBidiStreaming<RequestType, ResponseType>( | |||
|     call: Http2ServerCallStream<RequestType, ResponseType>, | ||||
|     handler: BidiStreamingHandler<RequestType, ResponseType>, | ||||
|     metadata: Metadata): void { | ||||
|   throw new Error('not implemented yet'); | ||||
|   const stream = new ServerDuplexStreamImpl<RequestType, ResponseType>( | ||||
|       call, metadata, handler.serialize, handler.deserialize); | ||||
| 
 | ||||
|   if (call.cancelled) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   handler.func(stream); | ||||
| } | ||||
|  |  | |||
|  | @ -147,6 +147,20 @@ describe('Client malformed response handling', () => { | |||
|       done(); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   it('should get an INTERNAL status with a bidi stream call', (done) => { | ||||
|     const call = client.bidiStream(); | ||||
| 
 | ||||
|     call.on('data', noop); | ||||
|     call.on('error', (err: ServiceError) => { | ||||
|       assert(err); | ||||
|       assert.strictEqual(err.code, grpc.status.INTERNAL); | ||||
|       done(); | ||||
|     }); | ||||
| 
 | ||||
|     call.write({}); | ||||
|     call.end(); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| describe('Server serialization failure handling', () => { | ||||
|  | @ -444,6 +458,23 @@ describe('Other conditions', () => { | |||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('should respond correctly to a bidi stream', (done) => { | ||||
|       const call = misbehavingClient.bidiStream(); | ||||
| 
 | ||||
|       call.on('data', (data: any) => { | ||||
|         assert.fail(data); | ||||
|       }); | ||||
| 
 | ||||
|       call.on('error', (err: ServiceError) => { | ||||
|         assert(err); | ||||
|         assert.strictEqual(err.code, grpc.status.INTERNAL); | ||||
|         done(); | ||||
|       }); | ||||
| 
 | ||||
|       call.write(badArg); | ||||
|       call.end(); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Trailing metadata', () => { | ||||
|  | @ -561,6 +592,33 @@ describe('Other conditions', () => { | |||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('should be present when a bidi stream succeeds', (done) => { | ||||
|       const call = client.bidiStream(); | ||||
| 
 | ||||
|       call.write({error: false}); | ||||
|       call.write({error: false}); | ||||
|       call.end(); | ||||
|       call.on('data', noop); | ||||
|       call.on('status', (status: grpc.StatusObject) => { | ||||
|         assert.strictEqual(status.code, grpc.status.OK); | ||||
|         assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); | ||||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('should be present when a bidi stream fails', (done) => { | ||||
|       const call = client.bidiStream(); | ||||
| 
 | ||||
|       call.write({error: false}); | ||||
|       call.write({error: true}); | ||||
|       call.end(); | ||||
|       call.on('data', noop); | ||||
|       call.on('error', (error: ServiceError) => { | ||||
|         assert.deepStrictEqual(error.metadata.get('trailer-present'), ['yes']); | ||||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Error object should contain the status', () => { | ||||
|  | @ -597,6 +655,20 @@ describe('Other conditions', () => { | |||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('for a bidi stream call', (done) => { | ||||
|       const call = client.bidiStream(); | ||||
| 
 | ||||
|       call.write({error: false}); | ||||
|       call.write({error: true}); | ||||
|       call.end(); | ||||
|       call.on('data', noop); | ||||
|       call.on('error', (error: ServiceError) => { | ||||
|         assert.strictEqual(error.code, grpc.status.UNKNOWN); | ||||
|         assert.strictEqual(error.details, 'Requested error'); | ||||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('for a UTF-8 error message', (done) => { | ||||
|       client.unary( | ||||
|           {error: true, message: '測試字符串'}, | ||||
|  |  | |||
|  | @ -286,6 +286,22 @@ describe('Server', () => { | |||
|         done(); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('should respond to a bidi call with UNIMPLEMENTED', (done) => { | ||||
|       const call = client.divMany(); | ||||
| 
 | ||||
|       call.on('data', (value: any) => { | ||||
|         assert.fail('No messages expected'); | ||||
|       }); | ||||
| 
 | ||||
|       call.on('error', (err: ServiceError) => { | ||||
|         assert(err); | ||||
|         assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); | ||||
|         done(); | ||||
|       }); | ||||
| 
 | ||||
|       call.end(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue