mirror of https://github.com/grpc/grpc.git
commit
a4880374f9
796 changed files with 24969 additions and 4555 deletions
@ -0,0 +1 @@ |
||||
This is the dynamic code generation variant of the Node examples. Code in these examples is generated at runtime using Protobuf.js. |
@ -0,0 +1,7 @@ |
||||
This is the static code generation variant of the Node examples. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the base directory of this package): |
||||
|
||||
```sh |
||||
cd ../protos |
||||
protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=grpc_node_plugin helloworld.proto |
||||
protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=grpc_node_plugin route_guide.proto |
||||
``` |
@ -0,0 +1,55 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, 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. |
||||
* |
||||
*/ |
||||
|
||||
var messages = require('./helloworld_pb'); |
||||
var services = require('./helloworld_grpc_pb'); |
||||
|
||||
var grpc = require('grpc'); |
||||
|
||||
function main() { |
||||
var client = new services.GreeterClient('localhost:50051', |
||||
grpc.credentials.createInsecure()); |
||||
var user; |
||||
if (process.argv.length >= 3) { |
||||
user = process.argv[2]; |
||||
} else { |
||||
user = 'world'; |
||||
} |
||||
var request = new messages.HelloRequest(); |
||||
request.setName(user); |
||||
client.sayHello(request, function(err, response) { |
||||
console.log('Greeting:', response.getMessage()); |
||||
}); |
||||
} |
||||
|
||||
main(); |
@ -0,0 +1,59 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, 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. |
||||
* |
||||
*/ |
||||
|
||||
var messages = require('./helloworld_pb'); |
||||
var services = require('./helloworld_grpc_pb'); |
||||
|
||||
var grpc = require('grpc'); |
||||
|
||||
/** |
||||
* Implements the SayHello RPC method. |
||||
*/ |
||||
function sayHello(call, callback) { |
||||
var reply = new messages.HelloReply(); |
||||
reply.setMessage('Hello ' + call.request.getName()); |
||||
callback(null, reply); |
||||
} |
||||
|
||||
/** |
||||
* Starts an RPC server that receives requests for the Greeter service at the |
||||
* sample server port |
||||
*/ |
||||
function main() { |
||||
var server = new grpc.Server(); |
||||
server.addService(services.GreeterService, {sayHello: sayHello}); |
||||
server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); |
||||
server.start(); |
||||
} |
||||
|
||||
main(); |
@ -0,0 +1,44 @@ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
'use strict'; |
||||
var grpc = require('grpc'); |
||||
var helloworld_pb = require('./helloworld_pb.js'); |
||||
|
||||
function serialize_HelloReply(arg) { |
||||
if (!(arg instanceof helloworld_pb.HelloReply)) { |
||||
throw new Error('Expected argument of type HelloReply'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_HelloReply(buffer_arg) { |
||||
return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_HelloRequest(arg) { |
||||
if (!(arg instanceof helloworld_pb.HelloRequest)) { |
||||
throw new Error('Expected argument of type HelloRequest'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_HelloRequest(buffer_arg) { |
||||
return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
|
||||
var GreeterService = exports.GreeterService = { |
||||
sayHello: { |
||||
path: '/helloworld.Greeter/SayHello', |
||||
requestStream: false, |
||||
responseStream: false, |
||||
requestType: helloworld_pb.HelloRequest, |
||||
responseType: helloworld_pb.HelloReply, |
||||
requestSerialize: serialize_HelloRequest, |
||||
requestDeserialize: deserialize_HelloRequest, |
||||
responseSerialize: serialize_HelloReply, |
||||
responseDeserialize: deserialize_HelloReply, |
||||
}, |
||||
}; |
||||
|
||||
exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService); |
@ -0,0 +1,332 @@ |
||||
/** |
||||
* @fileoverview |
||||
* @enhanceable |
||||
* @public |
||||
*/ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
var jspb = require('google-protobuf'); |
||||
var goog = jspb; |
||||
var global = Function('return this')(); |
||||
|
||||
goog.exportSymbol('proto.helloworld.HelloReply', null, global); |
||||
goog.exportSymbol('proto.helloworld.HelloRequest', null, global); |
||||
|
||||
/** |
||||
* Generated by JsPbCodeGenerator. |
||||
* @param {Array=} opt_data Optional initial data array, typically from a |
||||
* server response, or constructed directly in Javascript. The array is used |
||||
* in place and becomes part of the constructed object. It is not cloned. |
||||
* If no data is provided, the constructed object will be empty, but still |
||||
* valid. |
||||
* @extends {jspb.Message} |
||||
* @constructor |
||||
*/ |
||||
proto.helloworld.HelloRequest = function(opt_data) { |
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null); |
||||
}; |
||||
goog.inherits(proto.helloworld.HelloRequest, jspb.Message); |
||||
if (goog.DEBUG && !COMPILED) { |
||||
proto.helloworld.HelloRequest.displayName = 'proto.helloworld.HelloRequest'; |
||||
} |
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) { |
||||
/** |
||||
* Creates an object representation of this proto suitable for use in Soy templates. |
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name. |
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. |
||||
* For the list of reserved names please see: |
||||
* com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. |
||||
* @param {boolean=} opt_includeInstance Whether to include the JSPB instance |
||||
* for transitional soy proto support: http://goto/soy-param-migration
|
||||
* @return {!Object} |
||||
*/ |
||||
proto.helloworld.HelloRequest.prototype.toObject = function(opt_includeInstance) { |
||||
return proto.helloworld.HelloRequest.toObject(opt_includeInstance, this); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Static version of the {@see toObject} method. |
||||
* @param {boolean|undefined} includeInstance Whether to include the JSPB |
||||
* instance for transitional soy proto support: |
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.helloworld.HelloRequest} msg The msg instance to transform. |
||||
* @return {!Object} |
||||
*/ |
||||
proto.helloworld.HelloRequest.toObject = function(includeInstance, msg) { |
||||
var f, obj = { |
||||
name: msg.getName() |
||||
}; |
||||
|
||||
if (includeInstance) { |
||||
obj.$jspbMessageInstance = msg |
||||
} |
||||
return obj; |
||||
}; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Deserializes binary data (in protobuf wire format). |
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize. |
||||
* @return {!proto.helloworld.HelloRequest} |
||||
*/ |
||||
proto.helloworld.HelloRequest.deserializeBinary = function(bytes) { |
||||
var reader = new jspb.BinaryReader(bytes); |
||||
var msg = new proto.helloworld.HelloRequest; |
||||
return proto.helloworld.HelloRequest.deserializeBinaryFromReader(msg, reader); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Deserializes binary data (in protobuf wire format) from the |
||||
* given reader into the given message object. |
||||
* @param {!proto.helloworld.HelloRequest} msg The message object to deserialize into. |
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use. |
||||
* @return {!proto.helloworld.HelloRequest} |
||||
*/ |
||||
proto.helloworld.HelloRequest.deserializeBinaryFromReader = function(msg, reader) { |
||||
while (reader.nextField()) { |
||||
if (reader.isEndGroup()) { |
||||
break; |
||||
} |
||||
var field = reader.getFieldNumber(); |
||||
switch (field) { |
||||
case 1: |
||||
var value = /** @type {string} */ (reader.readString()); |
||||
msg.setName(value); |
||||
break; |
||||
default: |
||||
reader.skipField(); |
||||
break; |
||||
} |
||||
} |
||||
return msg; |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Class method variant: serializes the given message to binary data |
||||
* (in protobuf wire format), writing to the given BinaryWriter. |
||||
* @param {!proto.helloworld.HelloRequest} message |
||||
* @param {!jspb.BinaryWriter} writer |
||||
*/ |
||||
proto.helloworld.HelloRequest.serializeBinaryToWriter = function(message, writer) { |
||||
message.serializeBinaryToWriter(writer); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Serializes the message to binary data (in protobuf wire format). |
||||
* @return {!Uint8Array} |
||||
*/ |
||||
proto.helloworld.HelloRequest.prototype.serializeBinary = function() { |
||||
var writer = new jspb.BinaryWriter(); |
||||
this.serializeBinaryToWriter(writer); |
||||
return writer.getResultBuffer(); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Serializes the message to binary data (in protobuf wire format), |
||||
* writing to the given BinaryWriter. |
||||
* @param {!jspb.BinaryWriter} writer |
||||
*/ |
||||
proto.helloworld.HelloRequest.prototype.serializeBinaryToWriter = function (writer) { |
||||
var f = undefined; |
||||
f = this.getName(); |
||||
if (f.length > 0) { |
||||
writer.writeString( |
||||
1, |
||||
f |
||||
); |
||||
} |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Creates a deep clone of this proto. No data is shared with the original. |
||||
* @return {!proto.helloworld.HelloRequest} The clone. |
||||
*/ |
||||
proto.helloworld.HelloRequest.prototype.cloneMessage = function() { |
||||
return /** @type {!proto.helloworld.HelloRequest} */ (jspb.Message.cloneMessage(this)); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* optional string name = 1; |
||||
* @return {string} |
||||
*/ |
||||
proto.helloworld.HelloRequest.prototype.getName = function() { |
||||
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, "")); |
||||
}; |
||||
|
||||
|
||||
/** @param {string} value */ |
||||
proto.helloworld.HelloRequest.prototype.setName = function(value) { |
||||
jspb.Message.setField(this, 1, value); |
||||
}; |
||||
|
||||
|
||||
|
||||
/** |
||||
* Generated by JsPbCodeGenerator. |
||||
* @param {Array=} opt_data Optional initial data array, typically from a |
||||
* server response, or constructed directly in Javascript. The array is used |
||||
* in place and becomes part of the constructed object. It is not cloned. |
||||
* If no data is provided, the constructed object will be empty, but still |
||||
* valid. |
||||
* @extends {jspb.Message} |
||||
* @constructor |
||||
*/ |
||||
proto.helloworld.HelloReply = function(opt_data) { |
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null); |
||||
}; |
||||
goog.inherits(proto.helloworld.HelloReply, jspb.Message); |
||||
if (goog.DEBUG && !COMPILED) { |
||||
proto.helloworld.HelloReply.displayName = 'proto.helloworld.HelloReply'; |
||||
} |
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) { |
||||
/** |
||||
* Creates an object representation of this proto suitable for use in Soy templates. |
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name. |
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. |
||||
* For the list of reserved names please see: |
||||
* com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. |
||||
* @param {boolean=} opt_includeInstance Whether to include the JSPB instance |
||||
* for transitional soy proto support: http://goto/soy-param-migration
|
||||
* @return {!Object} |
||||
*/ |
||||
proto.helloworld.HelloReply.prototype.toObject = function(opt_includeInstance) { |
||||
return proto.helloworld.HelloReply.toObject(opt_includeInstance, this); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Static version of the {@see toObject} method. |
||||
* @param {boolean|undefined} includeInstance Whether to include the JSPB |
||||
* instance for transitional soy proto support: |
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.helloworld.HelloReply} msg The msg instance to transform. |
||||
* @return {!Object} |
||||
*/ |
||||
proto.helloworld.HelloReply.toObject = function(includeInstance, msg) { |
||||
var f, obj = { |
||||
message: msg.getMessage() |
||||
}; |
||||
|
||||
if (includeInstance) { |
||||
obj.$jspbMessageInstance = msg |
||||
} |
||||
return obj; |
||||
}; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Deserializes binary data (in protobuf wire format). |
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize. |
||||
* @return {!proto.helloworld.HelloReply} |
||||
*/ |
||||
proto.helloworld.HelloReply.deserializeBinary = function(bytes) { |
||||
var reader = new jspb.BinaryReader(bytes); |
||||
var msg = new proto.helloworld.HelloReply; |
||||
return proto.helloworld.HelloReply.deserializeBinaryFromReader(msg, reader); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Deserializes binary data (in protobuf wire format) from the |
||||
* given reader into the given message object. |
||||
* @param {!proto.helloworld.HelloReply} msg The message object to deserialize into. |
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use. |
||||
* @return {!proto.helloworld.HelloReply} |
||||
*/ |
||||
proto.helloworld.HelloReply.deserializeBinaryFromReader = function(msg, reader) { |
||||
while (reader.nextField()) { |
||||
if (reader.isEndGroup()) { |
||||
break; |
||||
} |
||||
var field = reader.getFieldNumber(); |
||||
switch (field) { |
||||
case 1: |
||||
var value = /** @type {string} */ (reader.readString()); |
||||
msg.setMessage(value); |
||||
break; |
||||
default: |
||||
reader.skipField(); |
||||
break; |
||||
} |
||||
} |
||||
return msg; |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Class method variant: serializes the given message to binary data |
||||
* (in protobuf wire format), writing to the given BinaryWriter. |
||||
* @param {!proto.helloworld.HelloReply} message |
||||
* @param {!jspb.BinaryWriter} writer |
||||
*/ |
||||
proto.helloworld.HelloReply.serializeBinaryToWriter = function(message, writer) { |
||||
message.serializeBinaryToWriter(writer); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Serializes the message to binary data (in protobuf wire format). |
||||
* @return {!Uint8Array} |
||||
*/ |
||||
proto.helloworld.HelloReply.prototype.serializeBinary = function() { |
||||
var writer = new jspb.BinaryWriter(); |
||||
this.serializeBinaryToWriter(writer); |
||||
return writer.getResultBuffer(); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Serializes the message to binary data (in protobuf wire format), |
||||
* writing to the given BinaryWriter. |
||||
* @param {!jspb.BinaryWriter} writer |
||||
*/ |
||||
proto.helloworld.HelloReply.prototype.serializeBinaryToWriter = function (writer) { |
||||
var f = undefined; |
||||
f = this.getMessage(); |
||||
if (f.length > 0) { |
||||
writer.writeString( |
||||
1, |
||||
f |
||||
); |
||||
} |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Creates a deep clone of this proto. No data is shared with the original. |
||||
* @return {!proto.helloworld.HelloReply} The clone. |
||||
*/ |
||||
proto.helloworld.HelloReply.prototype.cloneMessage = function() { |
||||
return /** @type {!proto.helloworld.HelloReply} */ (jspb.Message.cloneMessage(this)); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* optional string message = 1; |
||||
* @return {string} |
||||
*/ |
||||
proto.helloworld.HelloReply.prototype.getMessage = function() { |
||||
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, "")); |
||||
}; |
||||
|
||||
|
||||
/** @param {string} value */ |
||||
proto.helloworld.HelloReply.prototype.setMessage = function(value) { |
||||
jspb.Message.setField(this, 1, value); |
||||
}; |
||||
|
||||
|
||||
goog.object.extend(exports, proto.helloworld); |
@ -0,0 +1,5 @@ |
||||
#gRPC Basics: Node.js sample code |
||||
|
||||
The files in this folder are the samples used in [gRPC Basics: Node.js][], a detailed tutorial for using gRPC in Node.js. |
||||
|
||||
[gRPC Basics: Node.js]:http://www.grpc.io/docs/tutorials/basic/node.html |
@ -0,0 +1,247 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, 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. |
||||
* |
||||
*/ |
||||
|
||||
var messages = require('./route_guide_pb'); |
||||
var services = require('./route_guide_grpc_pb'); |
||||
|
||||
var async = require('async'); |
||||
var fs = require('fs'); |
||||
var parseArgs = require('minimist'); |
||||
var path = require('path'); |
||||
var _ = require('lodash'); |
||||
var grpc = require('grpc'); |
||||
|
||||
var client = new services.RouteGuideClient('localhost:50051', |
||||
grpc.credentials.createInsecure()); |
||||
|
||||
var COORD_FACTOR = 1e7; |
||||
|
||||
/** |
||||
* Run the getFeature demo. Calls getFeature with a point known to have a |
||||
* feature and a point known not to have a feature. |
||||
* @param {function} callback Called when this demo is complete |
||||
*/ |
||||
function runGetFeature(callback) { |
||||
var next = _.after(2, callback); |
||||
function featureCallback(error, feature) { |
||||
if (error) { |
||||
callback(error); |
||||
} |
||||
var latitude = feature.getLocation().getLatitude(); |
||||
var longitude = feature.getLocation().getLongitude(); |
||||
if (feature.getName() === '') { |
||||
console.log('Found no feature at ' + |
||||
latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR); |
||||
} else { |
||||
console.log('Found feature called "' + feature.getName() + '" at ' + |
||||
latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR); |
||||
} |
||||
next(); |
||||
} |
||||
var point1 = new messages.Point(); |
||||
point1.setLatitude(409146138); |
||||
point1.setLongitude(-746188906); |
||||
var point2 = new messages.Point(); |
||||
point2.setLatitude(0); |
||||
point2.setLongitude(0); |
||||
client.getFeature(point1, featureCallback); |
||||
client.getFeature(point2, featureCallback); |
||||
} |
||||
|
||||
/** |
||||
* Run the listFeatures demo. Calls listFeatures with a rectangle containing all |
||||
* of the features in the pre-generated database. Prints each response as it |
||||
* comes in. |
||||
* @param {function} callback Called when this demo is complete |
||||
*/ |
||||
function runListFeatures(callback) { |
||||
var rect = new messages.Rectangle(); |
||||
var lo = new messages.Point(); |
||||
lo.setLatitude(400000000); |
||||
lo.setLongitude(-750000000); |
||||
rect.setLo(lo); |
||||
var hi = new messages.Point(); |
||||
hi.setLatitude(420000000); |
||||
hi.setLongitude(-730000000); |
||||
rect.setHi(hi); |
||||
console.log('Looking for features between 40, -75 and 42, -73'); |
||||
var call = client.listFeatures(rect); |
||||
call.on('data', function(feature) { |
||||
console.log('Found feature called "' + feature.getName() + '" at ' + |
||||
feature.getLocation().getLatitude()/COORD_FACTOR + ', ' + |
||||
feature.getLocation().getLongitude()/COORD_FACTOR); |
||||
}); |
||||
call.on('end', callback); |
||||
} |
||||
|
||||
/** |
||||
* Run the recordRoute demo. Sends several randomly chosen points from the |
||||
* pre-generated feature database with a variable delay in between. Prints the |
||||
* statistics when they are sent from the server. |
||||
* @param {function} callback Called when this demo is complete |
||||
*/ |
||||
function runRecordRoute(callback) { |
||||
var argv = parseArgs(process.argv, { |
||||
string: 'db_path' |
||||
}); |
||||
fs.readFile(path.resolve(argv.db_path), function(err, data) { |
||||
if (err) callback(err); |
||||
// Transform the loaded features to Feature objects
|
||||
var feature_list = _.map(JSON.parse(data), function(value) { |
||||
var feature = new messages.Feature(); |
||||
feature.setName(value.name); |
||||
var location = new messages.Point(); |
||||
location.setLatitude(value.location.latitude); |
||||
location.setLongitude(value.location.longitude); |
||||
feature.setLocation(location); |
||||
return feature; |
||||
}); |
||||
|
||||
var num_points = 10; |
||||
var call = client.recordRoute(function(error, stats) { |
||||
if (error) { |
||||
callback(error); |
||||
} |
||||
console.log('Finished trip with', stats.getPointCount(), 'points'); |
||||
console.log('Passed', stats.getFeatureCount(), 'features'); |
||||
console.log('Travelled', stats.getDistance(), 'meters'); |
||||
console.log('It took', stats.getElapsedTime(), 'seconds'); |
||||
callback(); |
||||
}); |
||||
/** |
||||
* Constructs a function that asynchronously sends the given point and then |
||||
* delays sending its callback |
||||
* @param {messages.Point} location The point to send |
||||
* @return {function(function)} The function that sends the point |
||||
*/ |
||||
function pointSender(location) { |
||||
/** |
||||
* Sends the point, then calls the callback after a delay |
||||
* @param {function} callback Called when complete |
||||
*/ |
||||
return function(callback) { |
||||
console.log('Visiting point ' + location.getLatitude()/COORD_FACTOR + |
||||
', ' + location.getLongitude()/COORD_FACTOR); |
||||
call.write(location); |
||||
_.delay(callback, _.random(500, 1500)); |
||||
}; |
||||
} |
||||
var point_senders = []; |
||||
for (var i = 0; i < num_points; i++) { |
||||
var rand_point = feature_list[_.random(0, feature_list.length - 1)]; |
||||
point_senders[i] = pointSender(rand_point.getLocation()); |
||||
} |
||||
async.series(point_senders, function() { |
||||
call.end(); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Run the routeChat demo. Send some chat messages, and print any chat messages |
||||
* that are sent from the server. |
||||
* @param {function} callback Called when the demo is complete |
||||
*/ |
||||
function runRouteChat(callback) { |
||||
var call = client.routeChat(); |
||||
call.on('data', function(note) { |
||||
console.log('Got message "' + note.getMessage() + '" at ' + |
||||
note.getLocation().getLatitude() + ', ' + |
||||
note.getLocation().getLongitude()); |
||||
}); |
||||
|
||||
call.on('end', callback); |
||||
|
||||
var notes = [{ |
||||
location: { |
||||
latitude: 0, |
||||
longitude: 0 |
||||
}, |
||||
message: 'First message' |
||||
}, { |
||||
location: { |
||||
latitude: 0, |
||||
longitude: 1 |
||||
}, |
||||
message: 'Second message' |
||||
}, { |
||||
location: { |
||||
latitude: 1, |
||||
longitude: 0 |
||||
}, |
||||
message: 'Third message' |
||||
}, { |
||||
location: { |
||||
latitude: 0, |
||||
longitude: 0 |
||||
}, |
||||
message: 'Fourth message' |
||||
}]; |
||||
for (var i = 0; i < notes.length; i++) { |
||||
var note = notes[i]; |
||||
console.log('Sending message "' + note.message + '" at ' + |
||||
note.location.latitude + ', ' + note.location.longitude); |
||||
var noteMsg = new messages.RouteNote(); |
||||
noteMsg.setMessage(note.message); |
||||
var location = new messages.Point(); |
||||
location.setLatitude(note.location.latitude); |
||||
location.setLongitude(note.location.longitude); |
||||
noteMsg.setLocation(location); |
||||
call.write(noteMsg); |
||||
} |
||||
call.end(); |
||||
} |
||||
|
||||
/** |
||||
* Run all of the demos in order |
||||
*/ |
||||
function main() { |
||||
async.series([ |
||||
runGetFeature, |
||||
runListFeatures, |
||||
runRecordRoute, |
||||
runRouteChat |
||||
]); |
||||
} |
||||
|
||||
if (require.main === module) { |
||||
main(); |
||||
} |
||||
|
||||
exports.runGetFeature = runGetFeature; |
||||
|
||||
exports.runListFeatures = runListFeatures; |
||||
|
||||
exports.runRecordRoute = runRecordRoute; |
||||
|
||||
exports.runRouteChat = runRouteChat; |
@ -0,0 +1,601 @@ |
||||
[{ |
||||
"location": { |
||||
"latitude": 407838351, |
||||
"longitude": -746143763 |
||||
}, |
||||
"name": "Patriots Path, Mendham, NJ 07945, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 408122808, |
||||
"longitude": -743999179 |
||||
}, |
||||
"name": "101 New Jersey 10, Whippany, NJ 07981, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413628156, |
||||
"longitude": -749015468 |
||||
}, |
||||
"name": "U.S. 6, Shohola, PA 18458, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419999544, |
||||
"longitude": -740371136 |
||||
}, |
||||
"name": "5 Conners Road, Kingston, NY 12401, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414008389, |
||||
"longitude": -743951297 |
||||
}, |
||||
"name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419611318, |
||||
"longitude": -746524769 |
||||
}, |
||||
"name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406109563, |
||||
"longitude": -742186778 |
||||
}, |
||||
"name": "4001 Tremley Point Road, Linden, NJ 07036, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416802456, |
||||
"longitude": -742370183 |
||||
}, |
||||
"name": "352 South Mountain Road, Wallkill, NY 12589, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412950425, |
||||
"longitude": -741077389 |
||||
}, |
||||
"name": "Bailey Turn Road, Harriman, NY 10926, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412144655, |
||||
"longitude": -743949739 |
||||
}, |
||||
"name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415736605, |
||||
"longitude": -742847522 |
||||
}, |
||||
"name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413843930, |
||||
"longitude": -740501726 |
||||
}, |
||||
"name": "162 Merrill Road, Highland Mills, NY 10930, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410873075, |
||||
"longitude": -744459023 |
||||
}, |
||||
"name": "Clinton Road, West Milford, NJ 07480, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412346009, |
||||
"longitude": -744026814 |
||||
}, |
||||
"name": "16 Old Brook Lane, Warwick, NY 10990, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 402948455, |
||||
"longitude": -747903913 |
||||
}, |
||||
"name": "3 Drake Lane, Pennington, NJ 08534, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406337092, |
||||
"longitude": -740122226 |
||||
}, |
||||
"name": "6324 8th Avenue, Brooklyn, NY 11220, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406421967, |
||||
"longitude": -747727624 |
||||
}, |
||||
"name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416318082, |
||||
"longitude": -749677716 |
||||
}, |
||||
"name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415301720, |
||||
"longitude": -748416257 |
||||
}, |
||||
"name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 402647019, |
||||
"longitude": -747071791 |
||||
}, |
||||
"name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412567807, |
||||
"longitude": -741058078 |
||||
}, |
||||
"name": "New York State Reference Route 987E, Southfields, NY 10975, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416855156, |
||||
"longitude": -744420597 |
||||
}, |
||||
"name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404663628, |
||||
"longitude": -744820157 |
||||
}, |
||||
"name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407113723, |
||||
"longitude": -749746483 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 402133926, |
||||
"longitude": -743613249 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400273442, |
||||
"longitude": -741220915 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411236786, |
||||
"longitude": -744070769 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411633782, |
||||
"longitude": -746784970 |
||||
}, |
||||
"name": "211-225 Plains Road, Augusta, NJ 07822, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415830701, |
||||
"longitude": -742952812 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413447164, |
||||
"longitude": -748712898 |
||||
}, |
||||
"name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405047245, |
||||
"longitude": -749800722 |
||||
}, |
||||
"name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418858923, |
||||
"longitude": -746156790 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 417951888, |
||||
"longitude": -748484944 |
||||
}, |
||||
"name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407033786, |
||||
"longitude": -743977337 |
||||
}, |
||||
"name": "26 East 3rd Street, New Providence, NJ 07974, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 417548014, |
||||
"longitude": -740075041 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410395868, |
||||
"longitude": -744972325 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404615353, |
||||
"longitude": -745129803 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406589790, |
||||
"longitude": -743560121 |
||||
}, |
||||
"name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414653148, |
||||
"longitude": -740477477 |
||||
}, |
||||
"name": "18 Lannis Avenue, New Windsor, NY 12553, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405957808, |
||||
"longitude": -743255336 |
||||
}, |
||||
"name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411733589, |
||||
"longitude": -741648093 |
||||
}, |
||||
"name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412676291, |
||||
"longitude": -742606606 |
||||
}, |
||||
"name": "1270 Lakes Road, Monroe, NY 10950, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409224445, |
||||
"longitude": -748286738 |
||||
}, |
||||
"name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406523420, |
||||
"longitude": -742135517 |
||||
}, |
||||
"name": "652 Garden Street, Elizabeth, NJ 07202, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401827388, |
||||
"longitude": -740294537 |
||||
}, |
||||
"name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410564152, |
||||
"longitude": -743685054 |
||||
}, |
||||
"name": "13-17 Stanley Street, West Milford, NJ 07480, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 408472324, |
||||
"longitude": -740726046 |
||||
}, |
||||
"name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412452168, |
||||
"longitude": -740214052 |
||||
}, |
||||
"name": "5 White Oak Lane, Stony Point, NY 10980, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409146138, |
||||
"longitude": -746188906 |
||||
}, |
||||
"name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404701380, |
||||
"longitude": -744781745 |
||||
}, |
||||
"name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409642566, |
||||
"longitude": -746017679 |
||||
}, |
||||
"name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 408031728, |
||||
"longitude": -748645385 |
||||
}, |
||||
"name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413700272, |
||||
"longitude": -742135189 |
||||
}, |
||||
"name": "367 Prospect Road, Chester, NY 10918, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404310607, |
||||
"longitude": -740282632 |
||||
}, |
||||
"name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409319800, |
||||
"longitude": -746201391 |
||||
}, |
||||
"name": "11 Ward Street, Mount Arlington, NJ 07856, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406685311, |
||||
"longitude": -742108603 |
||||
}, |
||||
"name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419018117, |
||||
"longitude": -749142781 |
||||
}, |
||||
"name": "43 Dreher Road, Roscoe, NY 12776, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412856162, |
||||
"longitude": -745148837 |
||||
}, |
||||
"name": "Swan Street, Pine Island, NY 10969, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416560744, |
||||
"longitude": -746721964 |
||||
}, |
||||
"name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405314270, |
||||
"longitude": -749836354 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414219548, |
||||
"longitude": -743327440 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415534177, |
||||
"longitude": -742900616 |
||||
}, |
||||
"name": "565 Winding Hills Road, Montgomery, NY 12549, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406898530, |
||||
"longitude": -749127080 |
||||
}, |
||||
"name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407586880, |
||||
"longitude": -741670168 |
||||
}, |
||||
"name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400106455, |
||||
"longitude": -742870190 |
||||
}, |
||||
"name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400066188, |
||||
"longitude": -746793294 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418803880, |
||||
"longitude": -744102673 |
||||
}, |
||||
"name": "40 Mountain Road, Napanoch, NY 12458, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414204288, |
||||
"longitude": -747895140 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414777405, |
||||
"longitude": -740615601 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415464475, |
||||
"longitude": -747175374 |
||||
}, |
||||
"name": "48 North Road, Forestburgh, NY 12777, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404062378, |
||||
"longitude": -746376177 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405688272, |
||||
"longitude": -749285130 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400342070, |
||||
"longitude": -748788996 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401809022, |
||||
"longitude": -744157964 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404226644, |
||||
"longitude": -740517141 |
||||
}, |
||||
"name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410322033, |
||||
"longitude": -747871659 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407100674, |
||||
"longitude": -747742727 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418811433, |
||||
"longitude": -741718005 |
||||
}, |
||||
"name": "213 Bush Road, Stone Ridge, NY 12484, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415034302, |
||||
"longitude": -743850945 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411349992, |
||||
"longitude": -743694161 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404839914, |
||||
"longitude": -744759616 |
||||
}, |
||||
"name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414638017, |
||||
"longitude": -745957854 |
||||
}, |
||||
"name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412127800, |
||||
"longitude": -740173578 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401263460, |
||||
"longitude": -747964303 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412843391, |
||||
"longitude": -749086026 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418512773, |
||||
"longitude": -743067823 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404318328, |
||||
"longitude": -740835638 |
||||
}, |
||||
"name": "42-102 Main Street, Belford, NJ 07718, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419020746, |
||||
"longitude": -741172328 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404080723, |
||||
"longitude": -746119569 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401012643, |
||||
"longitude": -744035134 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404306372, |
||||
"longitude": -741079661 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 403966326, |
||||
"longitude": -748519297 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405002031, |
||||
"longitude": -748407866 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409532885, |
||||
"longitude": -742200683 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416851321, |
||||
"longitude": -742674555 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406411633, |
||||
"longitude": -741722051 |
||||
}, |
||||
"name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413069058, |
||||
"longitude": -744597778 |
||||
}, |
||||
"name": "261 Van Sickle Road, Goshen, NY 10924, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418465462, |
||||
"longitude": -746859398 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411733222, |
||||
"longitude": -744228360 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410248224, |
||||
"longitude": -747127767 |
||||
}, |
||||
"name": "3 Hasta Way, Newton, NJ 07860, USA" |
||||
}] |
@ -0,0 +1,110 @@ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
'use strict'; |
||||
var grpc = require('grpc'); |
||||
var route_guide_pb = require('./route_guide_pb.js'); |
||||
|
||||
function serialize_Feature(arg) { |
||||
if (!(arg instanceof route_guide_pb.Feature)) { |
||||
throw new Error('Expected argument of type Feature'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_Feature(buffer_arg) { |
||||
return route_guide_pb.Feature.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_Point(arg) { |
||||
if (!(arg instanceof route_guide_pb.Point)) { |
||||
throw new Error('Expected argument of type Point'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_Point(buffer_arg) { |
||||
return route_guide_pb.Point.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_Rectangle(arg) { |
||||
if (!(arg instanceof route_guide_pb.Rectangle)) { |
||||
throw new Error('Expected argument of type Rectangle'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_Rectangle(buffer_arg) { |
||||
return route_guide_pb.Rectangle.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_RouteNote(arg) { |
||||
if (!(arg instanceof route_guide_pb.RouteNote)) { |
||||
throw new Error('Expected argument of type RouteNote'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_RouteNote(buffer_arg) { |
||||
return route_guide_pb.RouteNote.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_RouteSummary(arg) { |
||||
if (!(arg instanceof route_guide_pb.RouteSummary)) { |
||||
throw new Error('Expected argument of type RouteSummary'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_RouteSummary(buffer_arg) { |
||||
return route_guide_pb.RouteSummary.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
|
||||
var RouteGuideService = exports.RouteGuideService = { |
||||
getFeature: { |
||||
path: '/routeguide.RouteGuide/GetFeature', |
||||
requestStream: false, |
||||
responseStream: false, |
||||
requestType: route_guide_pb.Point, |
||||
responseType: route_guide_pb.Feature, |
||||
requestSerialize: serialize_Point, |
||||
requestDeserialize: deserialize_Point, |
||||
responseSerialize: serialize_Feature, |
||||
responseDeserialize: deserialize_Feature, |
||||
}, |
||||
listFeatures: { |
||||
path: '/routeguide.RouteGuide/ListFeatures', |
||||
requestStream: false, |
||||
responseStream: true, |
||||
requestType: route_guide_pb.Rectangle, |
||||
responseType: route_guide_pb.Feature, |
||||
requestSerialize: serialize_Rectangle, |
||||
requestDeserialize: deserialize_Rectangle, |
||||
responseSerialize: serialize_Feature, |
||||
responseDeserialize: deserialize_Feature, |
||||
}, |
||||
recordRoute: { |
||||
path: '/routeguide.RouteGuide/RecordRoute', |
||||
requestStream: true, |
||||
responseStream: false, |
||||
requestType: route_guide_pb.Point, |
||||
responseType: route_guide_pb.RouteSummary, |
||||
requestSerialize: serialize_Point, |
||||
requestDeserialize: deserialize_Point, |
||||
responseSerialize: serialize_RouteSummary, |
||||
responseDeserialize: deserialize_RouteSummary, |
||||
}, |
||||
routeChat: { |
||||
path: '/routeguide.RouteGuide/RouteChat', |
||||
requestStream: true, |
||||
responseStream: true, |
||||
requestType: route_guide_pb.RouteNote, |
||||
responseType: route_guide_pb.RouteNote, |
||||
requestSerialize: serialize_RouteNote, |
||||
requestDeserialize: deserialize_RouteNote, |
||||
responseSerialize: serialize_RouteNote, |
||||
responseDeserialize: deserialize_RouteNote, |
||||
}, |
||||
}; |
||||
|
||||
exports.RouteGuideClient = grpc.makeGenericClientConstructor(RouteGuideService); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,261 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, 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. |
||||
* |
||||
*/ |
||||
|
||||
var messages = require('./route_guide_pb'); |
||||
var services = require('./route_guide_grpc_pb'); |
||||
|
||||
var fs = require('fs'); |
||||
var parseArgs = require('minimist'); |
||||
var path = require('path'); |
||||
var _ = require('lodash'); |
||||
var grpc = require('grpc'); |
||||
|
||||
var COORD_FACTOR = 1e7; |
||||
|
||||
/** |
||||
* For simplicity, a point is a record type that looks like |
||||
* {latitude: number, longitude: number}, and a feature is a record type that |
||||
* looks like {name: string, location: point}. feature objects with name==='' |
||||
* are points with no feature. |
||||
*/ |
||||
|
||||
/** |
||||
* List of feature objects at points that have been requested so far. |
||||
*/ |
||||
var feature_list = []; |
||||
|
||||
/** |
||||
* Get a feature object at the given point, or creates one if it does not exist. |
||||
* @param {point} point The point to check |
||||
* @return {feature} The feature object at the point. Note that an empty name |
||||
* indicates no feature |
||||
*/ |
||||
function checkFeature(point) { |
||||
var feature; |
||||
// Check if there is already a feature object for the given point
|
||||
for (var i = 0; i < feature_list.length; i++) { |
||||
feature = feature_list[i]; |
||||
if (feature.getLocation().getLatitude() === point.getLatitude() && |
||||
feature.getLocation().getLongitude() === point.getLongitude()) { |
||||
return feature; |
||||
} |
||||
} |
||||
var name = ''; |
||||
feature = new messages.Feature(); |
||||
feature.setName(name); |
||||
feature.setLocation(point); |
||||
return feature; |
||||
} |
||||
|
||||
/** |
||||
* getFeature request handler. Gets a request with a point, and responds with a |
||||
* feature object indicating whether there is a feature at that point. |
||||
* @param {EventEmitter} call Call object for the handler to process |
||||
* @param {function(Error, feature)} callback Response callback |
||||
*/ |
||||
function getFeature(call, callback) { |
||||
callback(null, checkFeature(call.request)); |
||||
} |
||||
|
||||
/** |
||||
* listFeatures request handler. Gets a request with two points, and responds |
||||
* with a stream of all features in the bounding box defined by those points. |
||||
* @param {Writable} call Writable stream for responses with an additional |
||||
* request property for the request value. |
||||
*/ |
||||
function listFeatures(call) { |
||||
var lo = call.request.getLo(); |
||||
var hi = call.request.getHi(); |
||||
var left = _.min([lo.getLongitude(), hi.getLongitude()]); |
||||
var right = _.max([lo.getLongitude(), hi.getLongitude()]); |
||||
var top = _.max([lo.getLatitude(), hi.getLatitude()]); |
||||
var bottom = _.min([lo.getLatitude(), hi.getLatitude()]); |
||||
// For each feature, check if it is in the given bounding box
|
||||
_.each(feature_list, function(feature) { |
||||
if (feature.getName() === '') { |
||||
return; |
||||
} |
||||
if (feature.getLocation().getLongitude() >= left && |
||||
feature.getLocation().getLongitude() <= right && |
||||
feature.getLocation().getLatitude() >= bottom && |
||||
feature.getLocation().getLatitude() <= top) { |
||||
call.write(feature); |
||||
} |
||||
}); |
||||
call.end(); |
||||
} |
||||
|
||||
/** |
||||
* Calculate the distance between two points using the "haversine" formula. |
||||
* This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
|
||||
* @param start The starting point |
||||
* @param end The end point |
||||
* @return The distance between the points in meters |
||||
*/ |
||||
function getDistance(start, end) { |
||||
function toRadians(num) { |
||||
return num * Math.PI / 180; |
||||
} |
||||
var lat1 = start.getLatitude() / COORD_FACTOR; |
||||
var lat2 = end.getLatitude() / COORD_FACTOR; |
||||
var lon1 = start.getLongitude() / COORD_FACTOR; |
||||
var lon2 = end.getLongitude() / COORD_FACTOR; |
||||
var R = 6371000; // metres
|
||||
var φ1 = toRadians(lat1); |
||||
var φ2 = toRadians(lat2); |
||||
var Δφ = toRadians(lat2-lat1); |
||||
var Δλ = toRadians(lon2-lon1); |
||||
|
||||
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + |
||||
Math.cos(φ1) * Math.cos(φ2) * |
||||
Math.sin(Δλ/2) * Math.sin(Δλ/2); |
||||
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); |
||||
|
||||
return R * c; |
||||
} |
||||
|
||||
/** |
||||
* recordRoute handler. Gets a stream of points, and responds with statistics |
||||
* about the "trip": number of points, number of known features visited, total |
||||
* distance traveled, and total time spent. |
||||
* @param {Readable} call The request point stream. |
||||
* @param {function(Error, routeSummary)} callback The callback to pass the |
||||
* response to |
||||
*/ |
||||
function recordRoute(call, callback) { |
||||
var point_count = 0; |
||||
var feature_count = 0; |
||||
var distance = 0; |
||||
var previous = null; |
||||
// Start a timer
|
||||
var start_time = process.hrtime(); |
||||
call.on('data', function(point) { |
||||
point_count += 1; |
||||
if (checkFeature(point).name !== '') { |
||||
feature_count += 1; |
||||
} |
||||
/* For each point after the first, add the incremental distance from the |
||||
* previous point to the total distance value */ |
||||
if (previous != null) { |
||||
distance += getDistance(previous, point); |
||||
} |
||||
previous = point; |
||||
}); |
||||
call.on('end', function() { |
||||
var summary = new messages.RouteSummary(); |
||||
summary.setPointCount(point_count); |
||||
summary.setFeatureCount(feature_count); |
||||
// Cast the distance to an integer
|
||||
summary.setDistance(distance|0); |
||||
// End the timer
|
||||
summary.setElapsedTime(process.hrtime(start_time)[0]); |
||||
callback(null, summary); |
||||
}); |
||||
} |
||||
|
||||
var route_notes = {}; |
||||
|
||||
/** |
||||
* Turn the point into a dictionary key. |
||||
* @param {point} point The point to use |
||||
* @return {string} The key for an object |
||||
*/ |
||||
function pointKey(point) { |
||||
return point.getLatitude() + ' ' + point.getLongitude(); |
||||
} |
||||
|
||||
/** |
||||
* routeChat handler. Receives a stream of message/location pairs, and responds |
||||
* with a stream of all previous messages at each of those locations. |
||||
* @param {Duplex} call The stream for incoming and outgoing messages |
||||
*/ |
||||
function routeChat(call) { |
||||
call.on('data', function(note) { |
||||
var key = pointKey(note.getLocation()); |
||||
/* For each note sent, respond with all previous notes that correspond to |
||||
* the same point */ |
||||
if (route_notes.hasOwnProperty(key)) { |
||||
_.each(route_notes[key], function(note) { |
||||
call.write(note); |
||||
}); |
||||
} else { |
||||
route_notes[key] = []; |
||||
} |
||||
// Then add the new note to the list
|
||||
route_notes[key].push(note); |
||||
}); |
||||
call.on('end', function() { |
||||
call.end(); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Get a new server with the handler functions in this file bound to the methods |
||||
* it serves. |
||||
* @return {Server} The new server object |
||||
*/ |
||||
function getServer() { |
||||
var server = new grpc.Server(); |
||||
server.addService(services.RouteGuideService, { |
||||
getFeature: getFeature, |
||||
listFeatures: listFeatures, |
||||
recordRoute: recordRoute, |
||||
routeChat: routeChat |
||||
}); |
||||
return server; |
||||
} |
||||
|
||||
if (require.main === module) { |
||||
// If this is run as a script, start a server on an unused port
|
||||
var routeServer = getServer(); |
||||
routeServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); |
||||
var argv = parseArgs(process.argv, { |
||||
string: 'db_path' |
||||
}); |
||||
fs.readFile(path.resolve(argv.db_path), function(err, data) { |
||||
if (err) throw err; |
||||
// Transform the loaded features to Feature objects
|
||||
feature_list = _.map(JSON.parse(data), function(value) { |
||||
var feature = new messages.Feature(); |
||||
feature.setName(value.name); |
||||
var location = new messages.Point(); |
||||
location.setLatitude(value.location.latitude); |
||||
location.setLongitude(value.location.longitude); |
||||
feature.setLocation(location); |
||||
return feature; |
||||
}); |
||||
routeServer.start(); |
||||
}); |
||||
} |
||||
|
||||
exports.getServer = getServer; |
@ -0,0 +1,67 @@ |
||||
/*
|
||||
* |
||||
* Copyright 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCXX_IMPL_SERVER_BUILDER_PLUGIN_H |
||||
#define GRPCXX_IMPL_SERVER_BUILDER_PLUGIN_H |
||||
|
||||
#include <memory> |
||||
|
||||
#include <grpc++/support/config.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
class ServerInitializer; |
||||
|
||||
class ServerBuilderPlugin { |
||||
public: |
||||
virtual ~ServerBuilderPlugin() {} |
||||
virtual grpc::string name() = 0; |
||||
|
||||
// InitServer will be called in ServerBuilder::BuildAndStart(), after the
|
||||
// Server instance is created.
|
||||
virtual void InitServer(ServerInitializer* si) = 0; |
||||
|
||||
// Finish will be called at the end of ServerBuilder::BuildAndStart().
|
||||
virtual void Finish(ServerInitializer* si) = 0; |
||||
|
||||
// ChangeArguments is an interface that can be used in
|
||||
// ServerBuilderOption::UpdatePlugins
|
||||
virtual void ChangeArguments(const grpc::string& name, void* value) = 0; |
||||
|
||||
virtual bool has_sync_methods() const { return false; } |
||||
virtual bool has_async_methods() const { return false; } |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // GRPCXX_IMPL_SERVER_BUILDER_PLUGIN_H
|
@ -0,0 +1,51 @@ |
||||
/*
|
||||
* |
||||
* Copyright 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_GRPC_CRONET_H |
||||
#define GRPC_GRPC_CRONET_H |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
GRPCAPI grpc_channel *grpc_cronet_secure_channel_create( |
||||
void *engine, const char *target, const grpc_channel_args *args, |
||||
void *reserved); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* GRPC_GRPC_CRONET_H */ |
@ -0,0 +1,69 @@ |
||||
/*
|
||||
* |
||||
* Copyright 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/impl/codegen/port_platform.h> |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/surface/channel.h" |
||||
#include "src/core/lib/transport/transport_impl.h" |
||||
|
||||
// Cronet transport object
|
||||
typedef struct cronet_transport { |
||||
grpc_transport base; // must be first element in this structure
|
||||
void *engine; |
||||
char *host; |
||||
} cronet_transport; |
||||
|
||||
extern grpc_transport_vtable grpc_cronet_vtable; |
||||
|
||||
GRPCAPI grpc_channel *grpc_cronet_secure_channel_create( |
||||
void *engine, const char *target, const grpc_channel_args *args, |
||||
void *reserved) { |
||||
cronet_transport *ct = gpr_malloc(sizeof(cronet_transport)); |
||||
ct->base.vtable = &grpc_cronet_vtable; |
||||
ct->engine = engine; |
||||
ct->host = gpr_malloc(strlen(target) + 1); |
||||
strcpy(ct->host, target); |
||||
gpr_log(GPR_DEBUG, |
||||
"grpc_create_cronet_transport: cronet_engine = %p, target=%s", engine, |
||||
ct->host); |
||||
|
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||
return grpc_channel_create(&exec_ctx, target, args, |
||||
GRPC_CLIENT_DIRECT_CHANNEL, (grpc_transport *)ct); |
||||
} |
@ -0,0 +1,85 @@ |
||||
/*
|
||||
* |
||||
* Copyright 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. |
||||
* |
||||
*/ |
||||
|
||||
/* This file has empty implementation of all the functions exposed by the cronet
|
||||
library, so we can build it in all environments */ |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h" |
||||
|
||||
#ifdef GRPC_COMPILE_WITH_CRONET |
||||
/* link with the real CRONET library in the build system */ |
||||
#else |
||||
/* Dummy implementation of cronet API just to test for build-ability */ |
||||
cronet_bidirectional_stream* cronet_bidirectional_stream_create( |
||||
cronet_engine* engine, void* annotation, |
||||
cronet_bidirectional_stream_callback* callback) { |
||||
GPR_ASSERT(0); |
||||
return NULL; |
||||
} |
||||
|
||||
int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream) { |
||||
GPR_ASSERT(0); |
||||
return 0; |
||||
} |
||||
|
||||
int cronet_bidirectional_stream_start( |
||||
cronet_bidirectional_stream* stream, const char* url, int priority, |
||||
const char* method, const cronet_bidirectional_stream_header_array* headers, |
||||
bool end_of_stream) { |
||||
GPR_ASSERT(0); |
||||
return 0; |
||||
} |
||||
|
||||
int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream, |
||||
char* buffer, int capacity) { |
||||
GPR_ASSERT(0); |
||||
return 0; |
||||
} |
||||
|
||||
int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream, |
||||
const char* buffer, int count, |
||||
bool end_of_stream) { |
||||
GPR_ASSERT(0); |
||||
return 0; |
||||
} |
||||
|
||||
int cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream) { |
||||
GPR_ASSERT(0); |
||||
return 0; |
||||
} |
||||
|
||||
#endif /* GRPC_COMPILE_WITH_CRONET */ |
@ -0,0 +1,640 @@ |
||||
/*
|
||||
* |
||||
* Copyright 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/impl/codegen/port_platform.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/host_port.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/slice_buffer.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/support/string.h" |
||||
#include "src/core/lib/surface/channel.h" |
||||
#include "src/core/lib/transport/metadata_batch.h" |
||||
#include "src/core/lib/transport/transport_impl.h" |
||||
#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h" |
||||
|
||||
#define GRPC_HEADER_SIZE_IN_BYTES 5 |
||||
|
||||
// Global flag that gets set with GRPC_TRACE env variable
|
||||
int grpc_cronet_trace = 1; |
||||
|
||||
// Cronet transport object
|
||||
struct grpc_cronet_transport { |
||||
grpc_transport base; /* must be first element in this structure */ |
||||
cronet_engine *engine; |
||||
char *host; |
||||
}; |
||||
|
||||
typedef struct grpc_cronet_transport grpc_cronet_transport; |
||||
|
||||
enum send_state { |
||||
CRONET_SEND_IDLE = 0, |
||||
CRONET_REQ_STARTED, |
||||
CRONET_SEND_HEADER, |
||||
CRONET_WRITE, |
||||
CRONET_WRITE_COMPLETED, |
||||
}; |
||||
|
||||
enum recv_state { |
||||
CRONET_RECV_IDLE = 0, |
||||
CRONET_RECV_READ_LENGTH, |
||||
CRONET_RECV_READ_DATA, |
||||
CRONET_RECV_CLOSED, |
||||
}; |
||||
|
||||
static const char *recv_state_name[] = { |
||||
"CRONET_RECV_IDLE", "CRONET_RECV_READ_LENGTH", "CRONET_RECV_READ_DATA,", |
||||
"CRONET_RECV_CLOSED"}; |
||||
|
||||
// Enum that identifies calling function.
|
||||
enum e_caller { |
||||
PERFORM_STREAM_OP, |
||||
ON_READ_COMPLETE, |
||||
ON_RESPONSE_HEADERS_RECEIVED, |
||||
ON_RESPONSE_TRAILERS_RECEIVED |
||||
}; |
||||
|
||||
enum callback_id { |
||||
CB_SEND_INITIAL_METADATA = 0, |
||||
CB_SEND_MESSAGE, |
||||
CB_SEND_TRAILING_METADATA, |
||||
CB_RECV_MESSAGE, |
||||
CB_RECV_INITIAL_METADATA, |
||||
CB_RECV_TRAILING_METADATA, |
||||
CB_NUM_CALLBACKS |
||||
}; |
||||
|
||||
struct stream_obj { |
||||
// we store received bytes here as they trickle in.
|
||||
gpr_slice_buffer write_slice_buffer; |
||||
cronet_bidirectional_stream *cbs; |
||||
gpr_slice slice; |
||||
gpr_slice_buffer read_slice_buffer; |
||||
struct grpc_slice_buffer_stream sbs; |
||||
char *read_buffer; |
||||
int remaining_read_bytes; |
||||
int total_read_bytes; |
||||
|
||||
char *write_buffer; |
||||
size_t write_buffer_size; |
||||
|
||||
// Hold the URL
|
||||
char *url; |
||||
|
||||
bool response_headers_received; |
||||
bool read_requested; |
||||
bool response_trailers_received; |
||||
bool read_closed; |
||||
|
||||
// Recv message stuff
|
||||
grpc_byte_buffer **recv_message; |
||||
// Initial metadata stuff
|
||||
grpc_metadata_batch *recv_initial_metadata; |
||||
// Trailing metadata stuff
|
||||
grpc_metadata_batch *recv_trailing_metadata; |
||||
grpc_chttp2_incoming_metadata_buffer imb; |
||||
|
||||
// This mutex protects receive state machine execution
|
||||
gpr_mu recv_mu; |
||||
// we can queue up up to 2 callbacks for each OP
|
||||
grpc_closure *callback_list[CB_NUM_CALLBACKS][2]; |
||||
|
||||
// storage for header
|
||||
cronet_bidirectional_stream_header *headers; |
||||
uint32_t num_headers; |
||||
cronet_bidirectional_stream_header_array header_array; |
||||
// state tracking
|
||||
enum recv_state cronet_recv_state; |
||||
enum send_state cronet_send_state; |
||||
}; |
||||
|
||||
typedef struct stream_obj stream_obj; |
||||
|
||||
static void next_send_step(stream_obj *s); |
||||
static void next_recv_step(stream_obj *s, enum e_caller caller); |
||||
|
||||
static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
||||
grpc_stream *gs, grpc_pollset *pollset) {} |
||||
|
||||
static void enqueue_callbacks(grpc_closure *callback_list[]) { |
||||
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||
if (callback_list[0]) { |
||||
grpc_exec_ctx_enqueue(&exec_ctx, callback_list[0], true, NULL); |
||||
callback_list[0] = NULL; |
||||
} |
||||
if (callback_list[1]) { |
||||
grpc_exec_ctx_enqueue(&exec_ctx, callback_list[1], true, NULL); |
||||
callback_list[1] = NULL; |
||||
} |
||||
grpc_exec_ctx_finish(&exec_ctx); |
||||
} |
||||
|
||||
static void on_canceled(cronet_bidirectional_stream *stream) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "on_canceled %p", stream); |
||||
} |
||||
} |
||||
|
||||
static void on_failed(cronet_bidirectional_stream *stream, int net_error) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "on_failed %p, error = %d", stream, net_error); |
||||
} |
||||
} |
||||
|
||||
static void on_succeeded(cronet_bidirectional_stream *stream) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "on_succeeded %p", stream); |
||||
} |
||||
} |
||||
|
||||
static void on_response_trailers_received( |
||||
cronet_bidirectional_stream *stream, |
||||
const cronet_bidirectional_stream_header_array *trailers) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "R: on_response_trailers_received"); |
||||
} |
||||
stream_obj *s = (stream_obj *)stream->annotation; |
||||
|
||||
memset(&s->imb, 0, sizeof(s->imb)); |
||||
grpc_chttp2_incoming_metadata_buffer_init(&s->imb); |
||||
unsigned int i = 0; |
||||
for (i = 0; i < trailers->count; i++) { |
||||
grpc_chttp2_incoming_metadata_buffer_add( |
||||
&s->imb, grpc_mdelem_from_metadata_strings( |
||||
grpc_mdstr_from_string(trailers->headers[i].key), |
||||
grpc_mdstr_from_string(trailers->headers[i].value))); |
||||
} |
||||
s->response_trailers_received = true; |
||||
next_recv_step(s, ON_RESPONSE_TRAILERS_RECEIVED); |
||||
} |
||||
|
||||
static void on_write_completed(cronet_bidirectional_stream *stream, |
||||
const char *data) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "W: on_write_completed"); |
||||
} |
||||
stream_obj *s = (stream_obj *)stream->annotation; |
||||
enqueue_callbacks(s->callback_list[CB_SEND_MESSAGE]); |
||||
s->cronet_send_state = CRONET_WRITE_COMPLETED; |
||||
next_send_step(s); |
||||
} |
||||
|
||||
static void process_recv_message(stream_obj *s, const uint8_t *recv_data) { |
||||
gpr_slice read_data_slice = gpr_slice_malloc((uint32_t)s->total_read_bytes); |
||||
uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice); |
||||
memcpy(dst_p, recv_data, (size_t)s->total_read_bytes); |
||||
gpr_slice_buffer_add(&s->read_slice_buffer, read_data_slice); |
||||
grpc_slice_buffer_stream_init(&s->sbs, &s->read_slice_buffer, 0); |
||||
*s->recv_message = (grpc_byte_buffer *)&s->sbs; |
||||
} |
||||
|
||||
static int parse_grpc_header(const uint8_t *data) { |
||||
const uint8_t *p = data + 1; |
||||
int length = 0; |
||||
length |= ((uint8_t)*p++) << 24; |
||||
length |= ((uint8_t)*p++) << 16; |
||||
length |= ((uint8_t)*p++) << 8; |
||||
length |= ((uint8_t)*p++); |
||||
return length; |
||||
} |
||||
|
||||
static void on_read_completed(cronet_bidirectional_stream *stream, char *data, |
||||
int count) { |
||||
stream_obj *s = (stream_obj *)stream->annotation; |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "R: on_read_completed count=%d, total=%d, remaining=%d", |
||||
count, s->total_read_bytes, s->remaining_read_bytes); |
||||
} |
||||
if (count > 0) { |
||||
GPR_ASSERT(s->recv_message); |
||||
s->remaining_read_bytes -= count; |
||||
next_recv_step(s, ON_READ_COMPLETE); |
||||
} else { |
||||
s->read_closed = true; |
||||
next_recv_step(s, ON_READ_COMPLETE); |
||||
} |
||||
} |
||||
|
||||
static void on_response_headers_received( |
||||
cronet_bidirectional_stream *stream, |
||||
const cronet_bidirectional_stream_header_array *headers, |
||||
const char *negotiated_protocol) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "R: on_response_headers_received"); |
||||
} |
||||
stream_obj *s = (stream_obj *)stream->annotation; |
||||
enqueue_callbacks(s->callback_list[CB_RECV_INITIAL_METADATA]); |
||||
s->response_headers_received = true; |
||||
next_recv_step(s, ON_RESPONSE_HEADERS_RECEIVED); |
||||
} |
||||
|
||||
static void on_request_headers_sent(cronet_bidirectional_stream *stream) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "W: on_request_headers_sent"); |
||||
} |
||||
stream_obj *s = (stream_obj *)stream->annotation; |
||||
enqueue_callbacks(s->callback_list[CB_SEND_INITIAL_METADATA]); |
||||
s->cronet_send_state = CRONET_SEND_HEADER; |
||||
next_send_step(s); |
||||
} |
||||
|
||||
// Callback function pointers (invoked by cronet in response to events)
|
||||
static cronet_bidirectional_stream_callback callbacks = { |
||||
on_request_headers_sent, |
||||
on_response_headers_received, |
||||
on_read_completed, |
||||
on_write_completed, |
||||
on_response_trailers_received, |
||||
on_succeeded, |
||||
on_failed, |
||||
on_canceled}; |
||||
|
||||
static void invoke_closing_callback(stream_obj *s) { |
||||
grpc_chttp2_incoming_metadata_buffer_publish(&s->imb, |
||||
s->recv_trailing_metadata); |
||||
if (s->callback_list[CB_RECV_TRAILING_METADATA]) { |
||||
enqueue_callbacks(s->callback_list[CB_RECV_TRAILING_METADATA]); |
||||
} |
||||
} |
||||
|
||||
static void set_recv_state(stream_obj *s, enum recv_state state) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "next_state = %s", recv_state_name[state]); |
||||
} |
||||
s->cronet_recv_state = state; |
||||
} |
||||
|
||||
// This is invoked from perform_stream_op, and all on_xxxx callbacks.
|
||||
static void next_recv_step(stream_obj *s, enum e_caller caller) { |
||||
gpr_mu_lock(&s->recv_mu); |
||||
switch (s->cronet_recv_state) { |
||||
case CRONET_RECV_IDLE: |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_IDLE"); |
||||
} |
||||
if (caller == PERFORM_STREAM_OP || |
||||
caller == ON_RESPONSE_HEADERS_RECEIVED) { |
||||
if (s->read_closed && s->response_trailers_received) { |
||||
invoke_closing_callback(s); |
||||
set_recv_state(s, CRONET_RECV_CLOSED); |
||||
} else if (s->response_headers_received == true && |
||||
s->read_requested == true) { |
||||
set_recv_state(s, CRONET_RECV_READ_LENGTH); |
||||
s->total_read_bytes = s->remaining_read_bytes = |
||||
GRPC_HEADER_SIZE_IN_BYTES; |
||||
GPR_ASSERT(s->read_buffer); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()"); |
||||
} |
||||
cronet_bidirectional_stream_read(s->cbs, s->read_buffer, |
||||
s->remaining_read_bytes); |
||||
} |
||||
} |
||||
break; |
||||
case CRONET_RECV_READ_LENGTH: |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_LENGTH"); |
||||
} |
||||
if (caller == ON_READ_COMPLETE) { |
||||
if (s->read_closed) { |
||||
invoke_closing_callback(s); |
||||
enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]); |
||||
set_recv_state(s, CRONET_RECV_CLOSED); |
||||
} else { |
||||
GPR_ASSERT(s->remaining_read_bytes == 0); |
||||
set_recv_state(s, CRONET_RECV_READ_DATA); |
||||
s->total_read_bytes = s->remaining_read_bytes = |
||||
parse_grpc_header((const uint8_t *)s->read_buffer); |
||||
s->read_buffer = |
||||
gpr_realloc(s->read_buffer, (uint32_t)s->remaining_read_bytes); |
||||
GPR_ASSERT(s->read_buffer); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()"); |
||||
} |
||||
cronet_bidirectional_stream_read(s->cbs, (char *)s->read_buffer, |
||||
s->remaining_read_bytes); |
||||
} |
||||
} |
||||
break; |
||||
case CRONET_RECV_READ_DATA: |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_DATA"); |
||||
} |
||||
if (caller == ON_READ_COMPLETE) { |
||||
if (s->remaining_read_bytes > 0) { |
||||
int offset = s->total_read_bytes - s->remaining_read_bytes; |
||||
GPR_ASSERT(s->read_buffer); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()"); |
||||
} |
||||
cronet_bidirectional_stream_read( |
||||
s->cbs, (char *)s->read_buffer + offset, s->remaining_read_bytes); |
||||
} else { |
||||
gpr_slice_buffer_init(&s->read_slice_buffer); |
||||
uint8_t *p = (uint8_t *)s->read_buffer; |
||||
process_recv_message(s, p); |
||||
set_recv_state(s, CRONET_RECV_IDLE); |
||||
enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]); |
||||
} |
||||
} |
||||
break; |
||||
case CRONET_RECV_CLOSED: |
||||
break; |
||||
default: |
||||
GPR_ASSERT(0); // Should not reach here
|
||||
break; |
||||
} |
||||
gpr_mu_unlock(&s->recv_mu); |
||||
} |
||||
|
||||
// This function takes the data from s->write_slice_buffer and assembles into
|
||||
// a contiguous byte stream with 5 byte gRPC header prepended.
|
||||
static void create_grpc_frame(stream_obj *s) { |
||||
gpr_slice slice = gpr_slice_buffer_take_first(&s->write_slice_buffer); |
||||
uint8_t *raw_data = GPR_SLICE_START_PTR(slice); |
||||
size_t length = GPR_SLICE_LENGTH(slice); |
||||
s->write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES; |
||||
s->write_buffer = gpr_realloc(s->write_buffer, s->write_buffer_size); |
||||
uint8_t *p = (uint8_t *)s->write_buffer; |
||||
// Append 5 byte header
|
||||
*p++ = 0; |
||||
*p++ = (uint8_t)(length >> 24); |
||||
*p++ = (uint8_t)(length >> 16); |
||||
*p++ = (uint8_t)(length >> 8); |
||||
*p++ = (uint8_t)(length); |
||||
// append actual data
|
||||
memcpy(p, raw_data, length); |
||||
} |
||||
|
||||
static void do_write(stream_obj *s) { |
||||
gpr_slice_buffer *sb = &s->write_slice_buffer; |
||||
GPR_ASSERT(sb->count <= 1); |
||||
if (sb->count > 0) { |
||||
create_grpc_frame(s); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write"); |
||||
} |
||||
cronet_bidirectional_stream_write(s->cbs, s->write_buffer, |
||||
(int)s->write_buffer_size, false); |
||||
} |
||||
} |
||||
|
||||
//
|
||||
static void next_send_step(stream_obj *s) { |
||||
switch (s->cronet_send_state) { |
||||
case CRONET_SEND_IDLE: |
||||
GPR_ASSERT( |
||||
s->cbs); // cronet_bidirectional_stream is not initialized yet.
|
||||
s->cronet_send_state = CRONET_REQ_STARTED; |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_start to %s", s->url); |
||||
} |
||||
cronet_bidirectional_stream_start(s->cbs, s->url, 0, "POST", |
||||
&s->header_array, false); |
||||
// we no longer need the memory that was allocated earlier.
|
||||
gpr_free(s->header_array.headers); |
||||
break; |
||||
case CRONET_SEND_HEADER: |
||||
do_write(s); |
||||
s->cronet_send_state = CRONET_WRITE; |
||||
break; |
||||
case CRONET_WRITE_COMPLETED: |
||||
do_write(s); |
||||
break; |
||||
default: |
||||
GPR_ASSERT(0); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void convert_metadata_to_cronet_headers(grpc_linked_mdelem *head, |
||||
const char *host, |
||||
stream_obj *s) { |
||||
grpc_linked_mdelem *curr = head; |
||||
// Walk the linked list and get number of header fields
|
||||
uint32_t num_headers_available = 0; |
||||
while (curr != NULL) { |
||||
curr = curr->next; |
||||
num_headers_available++; |
||||
} |
||||
// Allocate enough memory
|
||||
s->headers = (cronet_bidirectional_stream_header *)gpr_malloc( |
||||
sizeof(cronet_bidirectional_stream_header) * num_headers_available); |
||||
|
||||
// Walk the linked list again, this time copying the header fields.
|
||||
// s->num_headers
|
||||
// can be less than num_headers_available, as some headers are not used for
|
||||
// cronet
|
||||
curr = head; |
||||
s->num_headers = 0; |
||||
while (s->num_headers < num_headers_available) { |
||||
grpc_mdelem *mdelem = curr->md; |
||||
curr = curr->next; |
||||
const char *key = grpc_mdstr_as_c_string(mdelem->key); |
||||
const char *value = grpc_mdstr_as_c_string(mdelem->value); |
||||
if (strcmp(key, ":scheme") == 0 || strcmp(key, ":method") == 0 || |
||||
strcmp(key, ":authority") == 0) { |
||||
// Cronet populates these fields on its own.
|
||||
continue; |
||||
} |
||||
if (strcmp(key, ":path") == 0) { |
||||
// Create URL by appending :path value to the hostname
|
||||
gpr_asprintf(&s->url, "https://%s%s", host, value); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "extracted URL = %s", s->url); |
||||
} |
||||
continue; |
||||
} |
||||
s->headers[s->num_headers].key = key; |
||||
s->headers[s->num_headers].value = value; |
||||
s->num_headers++; |
||||
if (curr == NULL) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
||||
grpc_stream *gs, grpc_transport_stream_op *op) { |
||||
grpc_cronet_transport *ct = (grpc_cronet_transport *)gt; |
||||
GPR_ASSERT(ct->engine); |
||||
stream_obj *s = (stream_obj *)gs; |
||||
if (op->recv_trailing_metadata) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, |
||||
"perform_stream_op - recv_trailing_metadata: on_complete=%p", |
||||
op->on_complete); |
||||
} |
||||
s->recv_trailing_metadata = op->recv_trailing_metadata; |
||||
GPR_ASSERT(!s->callback_list[CB_RECV_TRAILING_METADATA][0]); |
||||
s->callback_list[CB_RECV_TRAILING_METADATA][0] = op->on_complete; |
||||
} |
||||
if (op->recv_message) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "perform_stream_op - recv_message: on_complete=%p", |
||||
op->on_complete); |
||||
} |
||||
s->recv_message = (grpc_byte_buffer **)op->recv_message; |
||||
GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][0]); |
||||
GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][1]); |
||||
s->callback_list[CB_RECV_MESSAGE][0] = op->recv_message_ready; |
||||
s->callback_list[CB_RECV_MESSAGE][1] = op->on_complete; |
||||
s->read_requested = true; |
||||
next_recv_step(s, PERFORM_STREAM_OP); |
||||
} |
||||
if (op->recv_initial_metadata) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "perform_stream_op - recv_initial_metadata:=%p", |
||||
op->on_complete); |
||||
} |
||||
s->recv_initial_metadata = op->recv_initial_metadata; |
||||
GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][0]); |
||||
GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][1]); |
||||
s->callback_list[CB_RECV_INITIAL_METADATA][0] = |
||||
op->recv_initial_metadata_ready; |
||||
s->callback_list[CB_RECV_INITIAL_METADATA][1] = op->on_complete; |
||||
} |
||||
if (op->send_initial_metadata) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, |
||||
"perform_stream_op - send_initial_metadata: on_complete=%p", |
||||
op->on_complete); |
||||
} |
||||
s->num_headers = 0; |
||||
convert_metadata_to_cronet_headers(op->send_initial_metadata->list.head, |
||||
ct->host, s); |
||||
s->header_array.count = s->num_headers; |
||||
s->header_array.capacity = s->num_headers; |
||||
s->header_array.headers = s->headers; |
||||
GPR_ASSERT(!s->callback_list[CB_SEND_INITIAL_METADATA][0]); |
||||
s->callback_list[CB_SEND_INITIAL_METADATA][0] = op->on_complete; |
||||
} |
||||
if (op->send_message) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "perform_stream_op - send_message: on_complete=%p", |
||||
op->on_complete); |
||||
} |
||||
grpc_byte_stream_next(exec_ctx, op->send_message, &s->slice, |
||||
op->send_message->length, NULL); |
||||
// Check that compression flag is not ON. We don't support compression yet.
|
||||
// TODO (makdharma): add compression support
|
||||
GPR_ASSERT(op->send_message->flags == 0); |
||||
gpr_slice_buffer_add(&s->write_slice_buffer, s->slice); |
||||
if (s->cbs == NULL) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_create"); |
||||
} |
||||
s->cbs = cronet_bidirectional_stream_create(ct->engine, s, &callbacks); |
||||
GPR_ASSERT(s->cbs); |
||||
s->read_closed = false; |
||||
s->response_trailers_received = false; |
||||
s->response_headers_received = false; |
||||
s->cronet_send_state = CRONET_SEND_IDLE; |
||||
s->cronet_recv_state = CRONET_RECV_IDLE; |
||||
} |
||||
GPR_ASSERT(!s->callback_list[CB_SEND_MESSAGE][0]); |
||||
s->callback_list[CB_SEND_MESSAGE][0] = op->on_complete; |
||||
next_send_step(s); |
||||
} |
||||
if (op->send_trailing_metadata) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, |
||||
"perform_stream_op - send_trailing_metadata: on_complete=%p", |
||||
op->on_complete); |
||||
} |
||||
GPR_ASSERT(!s->callback_list[CB_SEND_TRAILING_METADATA][0]); |
||||
s->callback_list[CB_SEND_TRAILING_METADATA][0] = op->on_complete; |
||||
if (s->cbs) { |
||||
// Send an "empty" write to the far end to signal that we're done.
|
||||
// This will induce the server to send down trailers.
|
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write"); |
||||
} |
||||
cronet_bidirectional_stream_write(s->cbs, "abc", 0, true); |
||||
} else { |
||||
// We never created a stream. This was probably an empty request.
|
||||
invoke_closing_callback(s); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
||||
grpc_stream *gs, grpc_stream_refcount *refcount, |
||||
const void *server_data) { |
||||
stream_obj *s = (stream_obj *)gs; |
||||
memset(s->callback_list, 0, sizeof(s->callback_list)); |
||||
s->cbs = NULL; |
||||
gpr_mu_init(&s->recv_mu); |
||||
s->read_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES); |
||||
s->write_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES); |
||||
gpr_slice_buffer_init(&s->write_slice_buffer); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "cronet_transport - init_stream"); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
||||
grpc_stream *gs, void *and_free_memory) { |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "Destroy stream"); |
||||
} |
||||
stream_obj *s = (stream_obj *)gs; |
||||
s->cbs = NULL; |
||||
gpr_free(s->read_buffer); |
||||
gpr_free(s->write_buffer); |
||||
gpr_free(s->url); |
||||
gpr_mu_destroy(&s->recv_mu); |
||||
if (and_free_memory) { |
||||
gpr_free(and_free_memory); |
||||
} |
||||
} |
||||
|
||||
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { |
||||
grpc_cronet_transport *ct = (grpc_cronet_transport *)gt; |
||||
gpr_free(ct->host); |
||||
if (grpc_cronet_trace) { |
||||
gpr_log(GPR_DEBUG, "Destroy transport"); |
||||
} |
||||
} |
||||
|
||||
const grpc_transport_vtable grpc_cronet_vtable = { |
||||
sizeof(stream_obj), "cronet_http", init_stream, |
||||
set_pollset_do_nothing, perform_stream_op, NULL, |
||||
destroy_stream, destroy_transport, NULL}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H |
||||
#define GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H |
||||
|
||||
#include "src/core/lib/iomgr/ev_posix.h" |
||||
|
||||
const grpc_event_engine_vtable *grpc_init_poll_posix(void); |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H */ |
@ -0,0 +1,151 @@ |
||||
// Copyright 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. |
||||
|
||||
// Service exported by server reflection |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package grpc.reflection.v1alpha; |
||||
|
||||
service ServerReflection { |
||||
// The reflection service is structured as a bidirectional stream, ensuring |
||||
// all related requests go to a single server. |
||||
rpc ServerReflectionInfo(stream ServerReflectionRequest) |
||||
returns (stream ServerReflectionResponse); |
||||
} |
||||
|
||||
// The message sent by the client when calling ServerReflectionInfo method. |
||||
message ServerReflectionRequest { |
||||
string host = 1; |
||||
// To use reflection service, the client should set one of the following |
||||
// fields in message_request. The server distinguishes requests by their |
||||
// defined field and then handles them using corresponding methods. |
||||
oneof message_request { |
||||
// Find a proto file by the file name. |
||||
string file_by_filename = 3; |
||||
|
||||
// Find the proto file that declares the given fully-qualified symbol name. |
||||
// This field should be a fully-qualified symbol name |
||||
// (e.g. <package>.<service>[.<method>] or <package>.<type>). |
||||
string file_containing_symbol = 4; |
||||
|
||||
// Find the proto file which defines an extension extending the given |
||||
// message type with the given field number. |
||||
ExtensionRequest file_containing_extension = 5; |
||||
|
||||
// Finds the tag numbers used by all known extensions of extendee_type, and |
||||
// appends them to ExtensionNumberResponse in an undefined order. |
||||
// Its corresponding method is best-effort: it's not guaranteed that the |
||||
// reflection service will implement this method, and it's not guaranteed |
||||
// that this method will provide all extensions. Returns |
||||
// StatusCode::UNIMPLEMENTED if it's not implemented. |
||||
// This field should be a fully-qualified type name. The format is |
||||
// <package>.<type> |
||||
string all_extension_numbers_of_type = 6; |
||||
|
||||
// List the full names of registered services. The content will not be |
||||
// checked. |
||||
string list_services = 7; |
||||
} |
||||
} |
||||
|
||||
// The type name and extension number sent by the client when requesting |
||||
// file_containing_extension. |
||||
message ExtensionRequest { |
||||
// Fully-qualified type name. The format should be <package>.<type> |
||||
string containing_type = 1; |
||||
int32 extension_number = 2; |
||||
} |
||||
|
||||
// The message sent by the server to answer ServerReflectionInfo method. |
||||
message ServerReflectionResponse { |
||||
string valid_host = 1; |
||||
ServerReflectionRequest original_request = 2; |
||||
// The server set one of the following fields accroding to the message_request |
||||
// in the request. |
||||
oneof message_response { |
||||
// This message is used to answer file_by_filename, file_containing_symbol, |
||||
// file_containing_extension requests with transitive dependencies. As |
||||
// the repeated label is not allowed in oneof fields, we use a |
||||
// FileDescriptorResponse message to encapsulate the repeated fields. |
||||
// The reflection service is allowed to avoid sending FileDescriptorProtos |
||||
// that were previously sent in response to earlier requests in the stream. |
||||
FileDescriptorResponse file_descriptor_response = 4; |
||||
|
||||
// This message is used to answer all_extension_numbers_of_type requst. |
||||
ExtensionNumberResponse all_extension_numbers_response = 5; |
||||
|
||||
// This message is used to answer list_services request. |
||||
ListServiceResponse list_services_response = 6; |
||||
|
||||
// This message is used when an error occurs. |
||||
ErrorResponse error_response = 7; |
||||
} |
||||
} |
||||
|
||||
// Serialized FileDescriptorProto messages sent by the server answering |
||||
// a file_by_filename, file_containing_symbol, or file_containing_extension |
||||
// request. |
||||
message FileDescriptorResponse { |
||||
// Serialized FileDescriptorProto messages. We avoid taking a dependency on |
||||
// descriptor.proto, which uses proto2 only features, by making them opaque |
||||
// bytes instead. |
||||
repeated bytes file_descriptor_proto = 1; |
||||
} |
||||
|
||||
// A list of extension numbers sent by the server answering |
||||
// all_extension_numbers_of_type request. |
||||
message ExtensionNumberResponse { |
||||
// Full name of the base type, including the package name. The format |
||||
// is <package>.<type> |
||||
string base_type_name = 1; |
||||
repeated int32 extension_number = 2; |
||||
} |
||||
|
||||
// A list of ServiceResponse sent by the server answering list_services request. |
||||
message ListServiceResponse { |
||||
// The information of each service may be expanded in the future, so we use |
||||
// ServiceResponse message to encapsulate it. |
||||
repeated ServiceResponse service = 1; |
||||
} |
||||
|
||||
// The information of a single service used by ListServiceResponse to answer |
||||
// list_services request. |
||||
message ServiceResponse { |
||||
// Full name of a registered service, including its package name. The format |
||||
// is <package>.<service> |
||||
string name = 1; |
||||
} |
||||
|
||||
// The error code and error message sent by the server when an error occurs. |
||||
message ErrorResponse { |
||||
// This field uses the error codes defined in grpc::StatusCode. |
||||
int32 error_code = 1; |
||||
string error_message = 2; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue