| Index: third_party/grpc/src/node/src/server.js
|
| diff --git a/third_party/grpc/src/node/src/server.js b/third_party/grpc/src/node/src/server.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0cf7ba34246564ac529e866ba97bea9006c4dc66
|
| --- /dev/null
|
| +++ b/third_party/grpc/src/node/src/server.js
|
| @@ -0,0 +1,765 @@
|
| +/*
|
| + *
|
| + * Copyright 2015-2016, Google Inc.
|
| + * All rights reserved.
|
| + *
|
| + * Redistribution and use in source and binary forms, with or without
|
| + * modification, are permitted provided that the following conditions are
|
| + * met:
|
| + *
|
| + * * Redistributions of source code must retain the above copyright
|
| + * notice, this list of conditions and the following disclaimer.
|
| + * * Redistributions in binary form must reproduce the above
|
| + * copyright notice, this list of conditions and the following disclaimer
|
| + * in the documentation and/or other materials provided with the
|
| + * distribution.
|
| + * * Neither the name of Google Inc. nor the names of its
|
| + * contributors may be used to endorse or promote products derived from
|
| + * this software without specific prior written permission.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| + *
|
| + */
|
| +
|
| +/**
|
| + * Server module
|
| + *
|
| + * This module contains all the server code for Node gRPC: both the Server
|
| + * class itself and the method handler code for all types of methods.
|
| + *
|
| + * For example, to create a Server, add a service, and start it:
|
| + *
|
| + * var server = new server_module.Server();
|
| + * server.addProtoService(protobuf_service_descriptor, service_implementation);
|
| + * server.bind('address:port', server_credential);
|
| + * server.start();
|
| + *
|
| + * @module
|
| + */
|
| +
|
| +'use strict';
|
| +
|
| +var _ = require('lodash');
|
| +
|
| +var grpc = require('./grpc_extension');
|
| +
|
| +var common = require('./common');
|
| +
|
| +var Metadata = require('./metadata');
|
| +
|
| +var stream = require('stream');
|
| +
|
| +var Readable = stream.Readable;
|
| +var Writable = stream.Writable;
|
| +var Duplex = stream.Duplex;
|
| +var util = require('util');
|
| +
|
| +var EventEmitter = require('events').EventEmitter;
|
| +
|
| +/**
|
| + * Handle an error on a call by sending it as a status
|
| + * @access private
|
| + * @param {grpc.Call} call The call to send the error on
|
| + * @param {Object} error The error object
|
| + */
|
| +function handleError(call, error) {
|
| + var statusMetadata = new Metadata();
|
| + var status = {
|
| + code: grpc.status.UNKNOWN,
|
| + details: 'Unknown Error'
|
| + };
|
| + if (error.hasOwnProperty('message')) {
|
| + status.details = error.message;
|
| + }
|
| + if (error.hasOwnProperty('code')) {
|
| + status.code = error.code;
|
| + if (error.hasOwnProperty('details')) {
|
| + status.details = error.details;
|
| + }
|
| + }
|
| + if (error.hasOwnProperty('metadata')) {
|
| + statusMetadata = error.metadata;
|
| + }
|
| + status.metadata = statusMetadata._getCoreRepresentation();
|
| + var error_batch = {};
|
| + if (!call.metadataSent) {
|
| + error_batch[grpc.opType.SEND_INITIAL_METADATA] =
|
| + (new Metadata())._getCoreRepresentation();
|
| + }
|
| + error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
|
| + call.startBatch(error_batch, function(){});
|
| +}
|
| +
|
| +/**
|
| + * Send a response to a unary or client streaming call.
|
| + * @access private
|
| + * @param {grpc.Call} call The call to respond on
|
| + * @param {*} value The value to respond with
|
| + * @param {function(*):Buffer=} serialize Serialization function for the
|
| + * response
|
| + * @param {Metadata=} metadata Optional trailing metadata to send with status
|
| + * @param {number=} flags Flags for modifying how the message is sent.
|
| + * Defaults to 0.
|
| + */
|
| +function sendUnaryResponse(call, value, serialize, metadata, flags) {
|
| + var end_batch = {};
|
| + var statusMetadata = new Metadata();
|
| + var status = {
|
| + code: grpc.status.OK,
|
| + details: 'OK'
|
| + };
|
| + if (metadata) {
|
| + statusMetadata = metadata;
|
| + }
|
| + status.metadata = statusMetadata._getCoreRepresentation();
|
| + if (!call.metadataSent) {
|
| + end_batch[grpc.opType.SEND_INITIAL_METADATA] =
|
| + (new Metadata())._getCoreRepresentation();
|
| + call.metadataSent = true;
|
| + }
|
| + var message = serialize(value);
|
| + message.grpcWriteFlags = flags;
|
| + end_batch[grpc.opType.SEND_MESSAGE] = message;
|
| + end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
|
| + call.startBatch(end_batch, function (){});
|
| +}
|
| +
|
| +/**
|
| + * Initialize a writable stream. This is used for both the writable and duplex
|
| + * stream constructors.
|
| + * @access private
|
| + * @param {Writable} stream The stream to set up
|
| + * @param {function(*):Buffer=} Serialization function for responses
|
| + */
|
| +function setUpWritable(stream, serialize) {
|
| + stream.finished = false;
|
| + stream.status = {
|
| + code : grpc.status.OK,
|
| + details : 'OK',
|
| + metadata : new Metadata()
|
| + };
|
| + stream.serialize = common.wrapIgnoreNull(serialize);
|
| + function sendStatus() {
|
| + var batch = {};
|
| + if (!stream.call.metadataSent) {
|
| + stream.call.metadataSent = true;
|
| + batch[grpc.opType.SEND_INITIAL_METADATA] =
|
| + (new Metadata())._getCoreRepresentation();
|
| + }
|
| +
|
| + if (stream.status.metadata) {
|
| + stream.status.metadata = stream.status.metadata._getCoreRepresentation();
|
| + }
|
| + batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status;
|
| + stream.call.startBatch(batch, function(){});
|
| + }
|
| + stream.on('finish', sendStatus);
|
| + /**
|
| + * Set the pending status to a given error status. If the error does not have
|
| + * code or details properties, the code will be set to grpc.status.UNKNOWN
|
| + * and the details will be set to 'Unknown Error'.
|
| + * @param {Error} err The error object
|
| + */
|
| + function setStatus(err) {
|
| + var code = grpc.status.UNKNOWN;
|
| + var details = 'Unknown Error';
|
| + var metadata = new Metadata();
|
| + if (err.hasOwnProperty('message')) {
|
| + details = err.message;
|
| + }
|
| + if (err.hasOwnProperty('code')) {
|
| + code = err.code;
|
| + if (err.hasOwnProperty('details')) {
|
| + details = err.details;
|
| + }
|
| + }
|
| + if (err.hasOwnProperty('metadata')) {
|
| + metadata = err.metadata;
|
| + }
|
| + stream.status = {code: code, details: details, metadata: metadata};
|
| + }
|
| + /**
|
| + * Terminate the call. This includes indicating that reads are done, draining
|
| + * all pending writes, and sending the given error as a status
|
| + * @param {Error} err The error object
|
| + * @this GrpcServerStream
|
| + */
|
| + function terminateCall(err) {
|
| + // Drain readable data
|
| + setStatus(err);
|
| + stream.end();
|
| + }
|
| + stream.on('error', terminateCall);
|
| + /**
|
| + * Override of Writable#end method that allows for sending metadata with a
|
| + * success status.
|
| + * @param {Metadata=} metadata Metadata to send with the status
|
| + */
|
| + stream.end = function(metadata) {
|
| + if (metadata) {
|
| + stream.status.metadata = metadata;
|
| + }
|
| + Writable.prototype.end.call(this);
|
| + };
|
| +}
|
| +
|
| +/**
|
| + * Initialize a readable stream. This is used for both the readable and duplex
|
| + * stream constructors.
|
| + * @access private
|
| + * @param {Readable} stream The stream to initialize
|
| + * @param {function(Buffer):*=} deserialize Deserialization function for
|
| + * incoming data.
|
| + */
|
| +function setUpReadable(stream, deserialize) {
|
| + stream.deserialize = common.wrapIgnoreNull(deserialize);
|
| + stream.finished = false;
|
| + stream.reading = false;
|
| +
|
| + stream.terminate = function() {
|
| + stream.finished = true;
|
| + stream.on('data', function() {});
|
| + };
|
| +
|
| + stream.on('cancelled', function() {
|
| + stream.terminate();
|
| + });
|
| +}
|
| +
|
| +util.inherits(ServerUnaryCall, EventEmitter);
|
| +
|
| +function ServerUnaryCall(call) {
|
| + EventEmitter.call(this);
|
| + this.call = call;
|
| +}
|
| +
|
| +util.inherits(ServerWritableStream, Writable);
|
| +
|
| +/**
|
| + * A stream that the server can write to. Used for calls that are streaming from
|
| + * the server side.
|
| + * @constructor
|
| + * @param {grpc.Call} call The call object to send data with
|
| + * @param {function(*):Buffer=} serialize Serialization function for writes
|
| + */
|
| +function ServerWritableStream(call, serialize) {
|
| + Writable.call(this, {objectMode: true});
|
| + this.call = call;
|
| +
|
| + this.finished = false;
|
| + setUpWritable(this, serialize);
|
| +}
|
| +
|
| +/**
|
| + * Start writing a chunk of data. This is an implementation of a method required
|
| + * for implementing stream.Writable.
|
| + * @access private
|
| + * @param {Buffer} chunk The chunk of data to write
|
| + * @param {string} encoding Used to pass write flags
|
| + * @param {function(Error=)} callback Callback to indicate that the write is
|
| + * complete
|
| + */
|
| +function _write(chunk, encoding, callback) {
|
| + /* jshint validthis: true */
|
| + var batch = {};
|
| + var self = this;
|
| + if (!this.call.metadataSent) {
|
| + batch[grpc.opType.SEND_INITIAL_METADATA] =
|
| + (new Metadata())._getCoreRepresentation();
|
| + this.call.metadataSent = true;
|
| + }
|
| + var message = this.serialize(chunk);
|
| + if (_.isFinite(encoding)) {
|
| + /* Attach the encoding if it is a finite number. This is the closest we
|
| + * can get to checking that it is valid flags */
|
| + message.grpcWriteFlags = encoding;
|
| + }
|
| + batch[grpc.opType.SEND_MESSAGE] = message;
|
| + this.call.startBatch(batch, function(err, value) {
|
| + if (err) {
|
| + self.emit('error', err);
|
| + return;
|
| + }
|
| + callback();
|
| + });
|
| +}
|
| +
|
| +ServerWritableStream.prototype._write = _write;
|
| +
|
| +util.inherits(ServerReadableStream, Readable);
|
| +
|
| +/**
|
| + * A stream that the server can read from. Used for calls that are streaming
|
| + * from the client side.
|
| + * @constructor
|
| + * @param {grpc.Call} call The call object to read data with
|
| + * @param {function(Buffer):*=} deserialize Deserialization function for reads
|
| + */
|
| +function ServerReadableStream(call, deserialize) {
|
| + Readable.call(this, {objectMode: true});
|
| + this.call = call;
|
| + setUpReadable(this, deserialize);
|
| +}
|
| +
|
| +/**
|
| + * Start reading from the gRPC data source. This is an implementation of a
|
| + * method required for implementing stream.Readable
|
| + * @access private
|
| + * @param {number} size Ignored
|
| + */
|
| +function _read(size) {
|
| + /* jshint validthis: true */
|
| + var self = this;
|
| + /**
|
| + * Callback to be called when a READ event is received. Pushes the data onto
|
| + * the read queue and starts reading again if applicable
|
| + * @param {grpc.Event} event READ event object
|
| + */
|
| + function readCallback(err, event) {
|
| + if (err) {
|
| + self.terminate();
|
| + return;
|
| + }
|
| + if (self.finished) {
|
| + self.push(null);
|
| + return;
|
| + }
|
| + var data = event.read;
|
| + var deserialized;
|
| + try {
|
| + deserialized = self.deserialize(data);
|
| + } catch (e) {
|
| + e.code = grpc.status.INVALID_ARGUMENT;
|
| + self.emit('error', e);
|
| + return;
|
| + }
|
| + if (self.push(deserialized) && data !== null) {
|
| + var read_batch = {};
|
| + read_batch[grpc.opType.RECV_MESSAGE] = true;
|
| + self.call.startBatch(read_batch, readCallback);
|
| + } else {
|
| + self.reading = false;
|
| + }
|
| + }
|
| + if (self.finished) {
|
| + self.push(null);
|
| + } else {
|
| + if (!self.reading) {
|
| + self.reading = true;
|
| + var batch = {};
|
| + batch[grpc.opType.RECV_MESSAGE] = true;
|
| + self.call.startBatch(batch, readCallback);
|
| + }
|
| + }
|
| +}
|
| +
|
| +ServerReadableStream.prototype._read = _read;
|
| +
|
| +util.inherits(ServerDuplexStream, Duplex);
|
| +
|
| +/**
|
| + * A stream that the server can read from or write to. Used for calls with
|
| + * duplex streaming.
|
| + * @constructor
|
| + * @param {grpc.Call} call Call object to proxy
|
| + * @param {function(*):Buffer=} serialize Serialization function for requests
|
| + * @param {function(Buffer):*=} deserialize Deserialization function for
|
| + * responses
|
| + */
|
| +function ServerDuplexStream(call, serialize, deserialize) {
|
| + Duplex.call(this, {objectMode: true});
|
| + this.call = call;
|
| + setUpWritable(this, serialize);
|
| + setUpReadable(this, deserialize);
|
| +}
|
| +
|
| +ServerDuplexStream.prototype._read = _read;
|
| +ServerDuplexStream.prototype._write = _write;
|
| +
|
| +/**
|
| + * Send the initial metadata for a writable stream.
|
| + * @param {Metadata} responseMetadata Metadata to send
|
| + */
|
| +function sendMetadata(responseMetadata) {
|
| + /* jshint validthis: true */
|
| + var self = this;
|
| + if (!this.call.metadataSent) {
|
| + this.call.metadataSent = true;
|
| + var batch = {};
|
| + batch[grpc.opType.SEND_INITIAL_METADATA] =
|
| + responseMetadata._getCoreRepresentation();
|
| + this.call.startBatch(batch, function(err) {
|
| + if (err) {
|
| + self.emit('error', err);
|
| + return;
|
| + }
|
| + });
|
| + }
|
| +}
|
| +
|
| +ServerUnaryCall.prototype.sendMetadata = sendMetadata;
|
| +ServerWritableStream.prototype.sendMetadata = sendMetadata;
|
| +ServerReadableStream.prototype.sendMetadata = sendMetadata;
|
| +ServerDuplexStream.prototype.sendMetadata = sendMetadata;
|
| +
|
| +/**
|
| + * Get the endpoint this call/stream is connected to.
|
| + * @return {string} The URI of the endpoint
|
| + */
|
| +function getPeer() {
|
| + /* jshint validthis: true */
|
| + return this.call.getPeer();
|
| +}
|
| +
|
| +ServerUnaryCall.prototype.getPeer = getPeer;
|
| +ServerReadableStream.prototype.getPeer = getPeer;
|
| +ServerWritableStream.prototype.getPeer = getPeer;
|
| +ServerDuplexStream.prototype.getPeer = getPeer;
|
| +
|
| +/**
|
| + * Wait for the client to close, then emit a cancelled event if the client
|
| + * cancelled.
|
| + */
|
| +function waitForCancel() {
|
| + /* jshint validthis: true */
|
| + var self = this;
|
| + var cancel_batch = {};
|
| + cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
|
| + self.call.startBatch(cancel_batch, function(err, result) {
|
| + if (err) {
|
| + self.emit('error', err);
|
| + }
|
| + if (result.cancelled) {
|
| + self.cancelled = true;
|
| + self.emit('cancelled');
|
| + }
|
| + });
|
| +}
|
| +
|
| +ServerUnaryCall.prototype.waitForCancel = waitForCancel;
|
| +ServerReadableStream.prototype.waitForCancel = waitForCancel;
|
| +ServerWritableStream.prototype.waitForCancel = waitForCancel;
|
| +ServerDuplexStream.prototype.waitForCancel = waitForCancel;
|
| +
|
| +/**
|
| + * Fully handle a unary call
|
| + * @access private
|
| + * @param {grpc.Call} call The call to handle
|
| + * @param {Object} handler Request handler object for the method that was called
|
| + * @param {Metadata} metadata Metadata from the client
|
| + */
|
| +function handleUnary(call, handler, metadata) {
|
| + var emitter = new ServerUnaryCall(call);
|
| + emitter.on('error', function(error) {
|
| + handleError(call, error);
|
| + });
|
| + emitter.metadata = metadata;
|
| + emitter.waitForCancel();
|
| + var batch = {};
|
| + batch[grpc.opType.RECV_MESSAGE] = true;
|
| + call.startBatch(batch, function(err, result) {
|
| + if (err) {
|
| + handleError(call, err);
|
| + return;
|
| + }
|
| + try {
|
| + emitter.request = handler.deserialize(result.read);
|
| + } catch (e) {
|
| + e.code = grpc.status.INVALID_ARGUMENT;
|
| + handleError(call, e);
|
| + return;
|
| + }
|
| + if (emitter.cancelled) {
|
| + return;
|
| + }
|
| + handler.func(emitter, function sendUnaryData(err, value, trailer, flags) {
|
| + if (err) {
|
| + if (trailer) {
|
| + err.metadata = trailer;
|
| + }
|
| + handleError(call, err);
|
| + } else {
|
| + sendUnaryResponse(call, value, handler.serialize, trailer, flags);
|
| + }
|
| + });
|
| + });
|
| +}
|
| +
|
| +/**
|
| + * Fully handle a server streaming call
|
| + * @access private
|
| + * @param {grpc.Call} call The call to handle
|
| + * @param {Object} handler Request handler object for the method that was called
|
| + * @param {Metadata} metadata Metadata from the client
|
| + */
|
| +function handleServerStreaming(call, handler, metadata) {
|
| + var stream = new ServerWritableStream(call, handler.serialize);
|
| + stream.waitForCancel();
|
| + stream.metadata = metadata;
|
| + var batch = {};
|
| + batch[grpc.opType.RECV_MESSAGE] = true;
|
| + call.startBatch(batch, function(err, result) {
|
| + if (err) {
|
| + stream.emit('error', err);
|
| + return;
|
| + }
|
| + try {
|
| + stream.request = handler.deserialize(result.read);
|
| + } catch (e) {
|
| + e.code = grpc.status.INVALID_ARGUMENT;
|
| + stream.emit('error', e);
|
| + return;
|
| + }
|
| + handler.func(stream);
|
| + });
|
| +}
|
| +
|
| +/**
|
| + * Fully handle a client streaming call
|
| + * @access private
|
| + * @param {grpc.Call} call The call to handle
|
| + * @param {Object} handler Request handler object for the method that was called
|
| + * @param {Metadata} metadata Metadata from the client
|
| + */
|
| +function handleClientStreaming(call, handler, metadata) {
|
| + var stream = new ServerReadableStream(call, handler.deserialize);
|
| + stream.on('error', function(error) {
|
| + handleError(call, error);
|
| + });
|
| + stream.waitForCancel();
|
| + stream.metadata = metadata;
|
| + handler.func(stream, function(err, value, trailer, flags) {
|
| + stream.terminate();
|
| + if (err) {
|
| + if (trailer) {
|
| + err.metadata = trailer;
|
| + }
|
| + handleError(call, err);
|
| + } else {
|
| + sendUnaryResponse(call, value, handler.serialize, trailer, flags);
|
| + }
|
| + });
|
| +}
|
| +
|
| +/**
|
| + * Fully handle a bidirectional streaming call
|
| + * @access private
|
| + * @param {grpc.Call} call The call to handle
|
| + * @param {Object} handler Request handler object for the method that was called
|
| + * @param {Metadata} metadata Metadata from the client
|
| + */
|
| +function handleBidiStreaming(call, handler, metadata) {
|
| + var stream = new ServerDuplexStream(call, handler.serialize,
|
| + handler.deserialize);
|
| + stream.waitForCancel();
|
| + stream.metadata = metadata;
|
| + handler.func(stream);
|
| +}
|
| +
|
| +var streamHandlers = {
|
| + unary: handleUnary,
|
| + server_stream: handleServerStreaming,
|
| + client_stream: handleClientStreaming,
|
| + bidi: handleBidiStreaming
|
| +};
|
| +
|
| +/**
|
| + * Constructs a server object that stores request handlers and delegates
|
| + * incoming requests to those handlers
|
| + * @constructor
|
| + * @param {Object=} options Options that should be passed to the internal server
|
| + * implementation
|
| + */
|
| +function Server(options) {
|
| + this.handlers = {};
|
| + var handlers = this.handlers;
|
| + var server = new grpc.Server(options);
|
| + this._server = server;
|
| + this.started = false;
|
| + /**
|
| + * Start the server and begin handling requests
|
| + * @this Server
|
| + */
|
| + this.start = function() {
|
| + if (this.started) {
|
| + throw new Error('Server is already running');
|
| + }
|
| + this.started = true;
|
| + server.start();
|
| + /**
|
| + * Handles the SERVER_RPC_NEW event. If there is a handler associated with
|
| + * the requested method, use that handler to respond to the request. Then
|
| + * wait for the next request
|
| + * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
|
| + */
|
| + function handleNewCall(err, event) {
|
| + if (err) {
|
| + return;
|
| + }
|
| + var details = event.new_call;
|
| + var call = details.call;
|
| + var method = details.method;
|
| + var metadata = Metadata._fromCoreRepresentation(details.metadata);
|
| + if (method === null) {
|
| + return;
|
| + }
|
| + server.requestCall(handleNewCall);
|
| + var handler;
|
| + if (handlers.hasOwnProperty(method)) {
|
| + handler = handlers[method];
|
| + } else {
|
| + var batch = {};
|
| + batch[grpc.opType.SEND_INITIAL_METADATA] =
|
| + (new Metadata())._getCoreRepresentation();
|
| + batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
| + code: grpc.status.UNIMPLEMENTED,
|
| + details: '',
|
| + metadata: {}
|
| + };
|
| + batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
|
| + call.startBatch(batch, function() {});
|
| + return;
|
| + }
|
| + streamHandlers[handler.type](call, handler, metadata);
|
| + }
|
| + server.requestCall(handleNewCall);
|
| + };
|
| +
|
| + /**
|
| + * Gracefully shuts down the server. The server will stop receiving new calls,
|
| + * and any pending calls will complete. The callback will be called when all
|
| + * pending calls have completed and the server is fully shut down. This method
|
| + * is idempotent with itself and forceShutdown.
|
| + * @param {function()} callback The shutdown complete callback
|
| + */
|
| + this.tryShutdown = function(callback) {
|
| + server.tryShutdown(callback);
|
| + };
|
| +
|
| + /**
|
| + * Forcibly shuts down the server. The server will stop receiving new calls
|
| + * and cancel all pending calls. When it returns, the server has shut down.
|
| + * This method is idempotent with itself and tryShutdown, and it will trigger
|
| + * any outstanding tryShutdown callbacks.
|
| + */
|
| + this.forceShutdown = function() {
|
| + server.forceShutdown();
|
| + };
|
| +}
|
| +
|
| +/**
|
| + * Registers a handler to handle the named method. Fails if there already is
|
| + * a handler for the given method. Returns true on success
|
| + * @param {string} name The name of the method that the provided function should
|
| + * handle/respond to.
|
| + * @param {function} handler Function that takes a stream of request values and
|
| + * returns a stream of response values
|
| + * @param {function(*):Buffer} serialize Serialization function for responses
|
| + * @param {function(Buffer):*} deserialize Deserialization function for requests
|
| + * @param {string} type The streaming type of method that this handles
|
| + * @return {boolean} True if the handler was set. False if a handler was already
|
| + * set for that name.
|
| + */
|
| +Server.prototype.register = function(name, handler, serialize, deserialize,
|
| + type) {
|
| + if (this.handlers.hasOwnProperty(name)) {
|
| + return false;
|
| + }
|
| + this.handlers[name] = {
|
| + func: handler,
|
| + serialize: serialize,
|
| + deserialize: deserialize,
|
| + type: type
|
| + };
|
| + return true;
|
| +};
|
| +
|
| +/**
|
| + * Add a service to the server, with a corresponding implementation. If you are
|
| + * generating this from a proto file, you should instead use
|
| + * addProtoService.
|
| + * @param {Object<String, *>} service The service descriptor, as
|
| + * {@link module:src/common.getProtobufServiceAttrs} returns
|
| + * @param {Object<String, function>} implementation Map of method names to
|
| + * method implementation for the provided service.
|
| + */
|
| +Server.prototype.addService = function(service, implementation) {
|
| + if (this.started) {
|
| + throw new Error('Can\'t add a service to a started server.');
|
| + }
|
| + var self = this;
|
| + _.each(service, function(attrs, name) {
|
| + var method_type;
|
| + if (attrs.requestStream) {
|
| + if (attrs.responseStream) {
|
| + method_type = 'bidi';
|
| + } else {
|
| + method_type = 'client_stream';
|
| + }
|
| + } else {
|
| + if (attrs.responseStream) {
|
| + method_type = 'server_stream';
|
| + } else {
|
| + method_type = 'unary';
|
| + }
|
| + }
|
| + if (implementation[name] === undefined) {
|
| + throw new Error('Method handler for ' + attrs.path +
|
| + ' not provided.');
|
| + }
|
| + var serialize = attrs.responseSerialize;
|
| + var deserialize = attrs.requestDeserialize;
|
| + var register_success = self.register(attrs.path,
|
| + _.bind(implementation[name],
|
| + implementation),
|
| + serialize, deserialize, method_type);
|
| + if (!register_success) {
|
| + throw new Error('Method handler for ' + attrs.path +
|
| + ' already provided.');
|
| + }
|
| + });
|
| +};
|
| +
|
| +/**
|
| + * Add a proto service to the server, with a corresponding implementation
|
| + * @param {Protobuf.Reflect.Service} service The proto service descriptor
|
| + * @param {Object<String, function>} implementation Map of method names to
|
| + * method implementation for the provided service.
|
| + */
|
| +Server.prototype.addProtoService = function(service, implementation) {
|
| + var options;
|
| + if (service.grpc_options) {
|
| + options = service.grpc_options;
|
| + }
|
| + this.addService(common.getProtobufServiceAttrs(service, options),
|
| + implementation);
|
| +};
|
| +
|
| +/**
|
| + * Binds the server to the given port, with SSL enabled if creds is given
|
| + * @param {string} port The port that the server should bind on, in the format
|
| + * "address:port"
|
| + * @param {ServerCredentials=} creds Server credential object to be used for
|
| + * SSL. Pass an insecure credentials object for an insecure port.
|
| + */
|
| +Server.prototype.bind = function(port, creds) {
|
| + if (this.started) {
|
| + throw new Error('Can\'t bind an already running server to an address');
|
| + }
|
| + return this._server.addHttp2Port(port, creds);
|
| +};
|
| +
|
| +/**
|
| + * @see module:src/server~Server
|
| + */
|
| +exports.Server = Server;
|
|
|