mirror of https://github.com/grpc/grpc.git
commit
80721b20ca
259 changed files with 5530 additions and 11995 deletions
@ -0,0 +1,15 @@ |
||||
gRPC Fail Fast Semantics |
||||
======================== |
||||
|
||||
Fail fast requests allow terminating requests (with status UNAVAILABLE) prior |
||||
to the deadline of the request being met. |
||||
|
||||
gRPC implementations of fail fast can terminate requests whenever a channel is |
||||
in the TRANSIENT_FAILURE or SHUTDOWN states. If the channel is in any other |
||||
state (CONNECTING, READY, or IDLE) the request should not be terminated. |
||||
|
||||
Fail fast SHOULD be the default for gRPC implementations, with an option to |
||||
switch to non fail fast. |
||||
|
||||
The opposite of fail fast is 'ignore connectivity'. |
||||
|
@ -1,39 +0,0 @@ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
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); |
@ -1,332 +0,0 @@ |
||||
/** |
||||
* @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); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,94 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
/* Posix code for gpr snprintf support. */ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_WIN32 |
||||
|
||||
/* Some platforms (namely msys) need wchar to be included BEFORE
|
||||
anything else, especially strsafe.h. */ |
||||
#include <wchar.h> |
||||
|
||||
#include <stdarg.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <strsafe.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/support/string.h" |
||||
|
||||
#if defined UNICODE || defined _UNICODE |
||||
LPTSTR |
||||
gpr_char_to_tchar(LPCSTR input) { |
||||
LPTSTR ret; |
||||
int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); |
||||
if (needed <= 0) return NULL; |
||||
ret = gpr_malloc((unsigned)needed * sizeof(TCHAR)); |
||||
MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed); |
||||
return ret; |
||||
} |
||||
|
||||
LPSTR |
||||
gpr_tchar_to_char(LPCTSTR input) { |
||||
LPSTR ret; |
||||
int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); |
||||
if (needed <= 0) return NULL; |
||||
ret = gpr_malloc((unsigned)needed); |
||||
WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL); |
||||
return ret; |
||||
} |
||||
#else |
||||
char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); } |
||||
|
||||
char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); } |
||||
#endif |
||||
|
||||
char *gpr_format_message(int messageid) { |
||||
LPTSTR tmessage; |
||||
char *message; |
||||
DWORD status = FormatMessage( |
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
||||
FORMAT_MESSAGE_IGNORE_INSERTS, |
||||
NULL, (DWORD)messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
||||
(LPTSTR)(&tmessage), 0, NULL); |
||||
if (status == 0) return gpr_strdup("Unable to retrieve error string"); |
||||
message = gpr_tchar_to_char(tmessage); |
||||
LocalFree(tmessage); |
||||
return message; |
||||
} |
||||
|
||||
#endif /* GPR_WIN32 */ |
@ -0,0 +1,73 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GPR_MSYS_TMPFILE |
||||
|
||||
#include <io.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <tchar.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/support/string_win32.h" |
||||
#include "src/core/lib/support/tmpfile.h" |
||||
|
||||
FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) { |
||||
FILE *result = NULL; |
||||
char tmp_filename[MAX_PATH]; |
||||
UINT success; |
||||
|
||||
if (tmp_filename_out != NULL) *tmp_filename_out = NULL; |
||||
|
||||
/* Generate a unique filename with our template + temporary path. */ |
||||
success = GetTempFileNameA(".", prefix, 0, tmp_filename); |
||||
fprintf(stderr, "success = %d\n", success); |
||||
|
||||
if (success) { |
||||
/* Open a file there. */ |
||||
result = fopen(tmp_filename, "wb+"); |
||||
fprintf(stderr, "result = %p\n", result); |
||||
} |
||||
if (result != NULL && tmp_filename_out) { |
||||
*tmp_filename_out = gpr_strdup(tmp_filename); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
#endif /* GPR_MSYS_TMPFILE */ |
@ -0,0 +1,54 @@ |
||||
#!/usr/bin/env node
|
||||
/* |
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
/** |
||||
* This file is required because package.json cannot reference a file that |
||||
* is not distributed with the package, and we use node-pre-gyp to distribute |
||||
* the plugin binary |
||||
*/ |
||||
|
||||
'use strict'; |
||||
|
||||
var path = require('path'); |
||||
var execFile = require('child_process').execFile; |
||||
|
||||
var protoc = path.resolve(__dirname, 'grpc_node_plugin'); |
||||
|
||||
execFile(protoc, process.argv.slice(2), function(error, stdout, stderr) { |
||||
if (error) { |
||||
throw error; |
||||
} |
||||
console.log(stdout); |
||||
console.log(stderr); |
||||
}); |
@ -0,0 +1,56 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#import "GRPCCall.h" |
||||
|
||||
/** Helpers for setting TLS Trusted Roots, Client Certificates, and Private Key */ |
||||
@interface GRPCCall (ChannelCredentials) |
||||
|
||||
/**
|
||||
* Use the provided @c pemRootCert as the set of trusted root Certificate Authorities for @c host. |
||||
*/ |
||||
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert |
||||
forHost:(nonnull NSString *)host |
||||
error:(NSError **)errorPtr; |
||||
/**
|
||||
* Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate |
||||
* Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be |
||||
* used. |
||||
*/ |
||||
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts |
||||
withPrivateKey:(nullable NSString *)pemPrivateKey |
||||
withCertChain:(nullable NSString *)pemCertChain |
||||
forHost:(nonnull NSString *)host |
||||
error:(NSError **)errorPtr; |
||||
|
||||
@end |
@ -0,0 +1,66 @@ |
||||
/* |
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
|
||||
#import "GRPCCall+ChannelCredentials.h" |
||||
|
||||
#import "private/GRPCHost.h" |
||||
|
||||
@implementation GRPCCall (ChannelCredentials) |
||||
|
||||
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts |
||||
withPrivateKey:(nullable NSString *)pemPrivateKey |
||||
withCertChain:(nullable NSString *)pemCertChain |
||||
forHost:(nonnull NSString *)host |
||||
error:(NSError **)errorPtr { |
||||
if (!host) { |
||||
[NSException raise:NSInvalidArgumentException |
||||
format:@"host must be provided."]; |
||||
} |
||||
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; |
||||
return [hostConfig setTLSPEMRootCerts:pemRootCerts |
||||
withPrivateKey:pemPrivateKey |
||||
withCertChain:pemCertChain |
||||
error:errorPtr]; |
||||
} |
||||
|
||||
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts |
||||
forHost:(nonnull NSString *)host |
||||
error:(NSError **)errorPtr { |
||||
return [GRPCCall setTLSPEMRootCerts:pemRootCerts |
||||
withPrivateKey:nil |
||||
withCertChain:nil |
||||
forHost:host |
||||
error:errorPtr]; |
||||
} |
||||
|
||||
@end |
@ -0,0 +1,75 @@ |
||||
// 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. |
||||
|
||||
// File detached comment 1 |
||||
|
||||
// File detached comment 2 |
||||
|
||||
// File leading comment 1 |
||||
syntax = "proto3"; |
||||
|
||||
// Ignored detached comment |
||||
|
||||
// Ignored package leading comment |
||||
package grpc.testing; |
||||
|
||||
message Request { |
||||
} |
||||
message Response { |
||||
} |
||||
|
||||
// ServiceA detached comment 1 |
||||
|
||||
// ServiceA detached comment 2 |
||||
|
||||
// ServiceA leading comment 1 |
||||
service ServiceA { |
||||
// MethodA1 leading comment 1 |
||||
rpc MethodA1(Request) returns (Response); // MethodA1 trailing comment 1 |
||||
|
||||
// MethodA2 detached leading comment 1 |
||||
|
||||
// Method A2 leading comment 1 |
||||
// Method A2 leading comment 2 |
||||
rpc MethodA2(stream Request) returns (Response); |
||||
// MethodA2 trailing comment 1 |
||||
} |
||||
// Ignored ServiceA trailing comment 1 |
||||
|
||||
// ServiceB leading comment 1 |
||||
service ServiceB { |
||||
// ServiceB trailing comment 1 |
||||
|
||||
// MethodB1 leading comment 1 |
||||
rpc MethodB1(Request) returns (Response); |
||||
// MethodB1 trailing comment 1 |
||||
} |
||||
// Ignored ServiceB trailing comment 2 |
||||
|
||||
// Ignored file trailing comment |
@ -1,363 +0,0 @@ |
||||
# 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. |
||||
|
||||
"""The RPC-service-side bridge between RPC Framework and GRPC-on-the-wire.""" |
||||
|
||||
import enum |
||||
import logging |
||||
import threading |
||||
import time |
||||
|
||||
from grpc._adapter import _common |
||||
from grpc._adapter import _intermediary_low as _low |
||||
from grpc.framework.base import interfaces as base_interfaces |
||||
from grpc.framework.base import null |
||||
from grpc.framework.foundation import activated |
||||
from grpc.framework.foundation import logging_pool |
||||
|
||||
_THREAD_POOL_SIZE = 10 |
||||
|
||||
|
||||
@enum.unique |
||||
class _LowWrite(enum.Enum): |
||||
"""The possible categories of low-level write state.""" |
||||
|
||||
OPEN = 'OPEN' |
||||
ACTIVE = 'ACTIVE' |
||||
CLOSED = 'CLOSED' |
||||
|
||||
|
||||
def _write(call, rpc_state, payload): |
||||
serialized_payload = rpc_state.serializer(payload) |
||||
if rpc_state.write.low is _LowWrite.OPEN: |
||||
call.write(serialized_payload, call, 0) |
||||
rpc_state.write.low = _LowWrite.ACTIVE |
||||
else: |
||||
rpc_state.write.pending.append(serialized_payload) |
||||
|
||||
|
||||
def _status(call, rpc_state): |
||||
call.status(_low.Status(_low.Code.OK, ''), call) |
||||
rpc_state.write.low = _LowWrite.CLOSED |
||||
|
||||
|
||||
class ForeLink(base_interfaces.ForeLink, activated.Activated): |
||||
"""A service-side bridge between RPC Framework and the C-ish _low code.""" |
||||
|
||||
def __init__( |
||||
self, pool, request_deserializers, response_serializers, |
||||
root_certificates, key_chain_pairs, port=None): |
||||
"""Constructor. |
||||
|
||||
Args: |
||||
pool: A thread pool. |
||||
request_deserializers: A dict from RPC method names to request object |
||||
deserializer behaviors. |
||||
response_serializers: A dict from RPC method names to response object |
||||
serializer behaviors. |
||||
root_certificates: The PEM-encoded client root certificates as a |
||||
bytestring or None. |
||||
key_chain_pairs: A sequence of PEM-encoded private key-certificate chain |
||||
pairs. |
||||
port: The port on which to serve, or None to have a port selected |
||||
automatically. |
||||
""" |
||||
self._condition = threading.Condition() |
||||
self._pool = pool |
||||
self._request_deserializers = request_deserializers |
||||
self._response_serializers = response_serializers |
||||
self._root_certificates = root_certificates |
||||
self._key_chain_pairs = key_chain_pairs |
||||
self._requested_port = port |
||||
|
||||
self._rear_link = null.NULL_REAR_LINK |
||||
self._completion_queue = None |
||||
self._server = None |
||||
self._rpc_states = {} |
||||
self._spinning = False |
||||
self._port = None |
||||
|
||||
def _on_stop_event(self): |
||||
self._spinning = False |
||||
self._condition.notify_all() |
||||
|
||||
def _on_service_acceptance_event(self, event, server): |
||||
"""Handle a service invocation event.""" |
||||
service_acceptance = event.service_acceptance |
||||
if service_acceptance is None: |
||||
return |
||||
|
||||
call = service_acceptance.call |
||||
call.accept(self._completion_queue, call) |
||||
# TODO(nathaniel): Metadata support. |
||||
call.premetadata() |
||||
call.read(call) |
||||
method = service_acceptance.method |
||||
|
||||
self._rpc_states[call] = _common.CommonRPCState( |
||||
_common.WriteState(_LowWrite.OPEN, _common.HighWrite.OPEN, []), 1, |
||||
self._request_deserializers[method], |
||||
self._response_serializers[method]) |
||||
|
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, 0, base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT, method, |
||||
base_interfaces.ServicedSubscription.Kind.FULL, None, None, |
||||
service_acceptance.deadline - time.time()) |
||||
self._rear_link.accept_front_to_back_ticket(ticket) |
||||
|
||||
server.service(None) |
||||
|
||||
def _on_read_event(self, event): |
||||
"""Handle data arriving during an RPC.""" |
||||
call = event.tag |
||||
rpc_state = self._rpc_states.get(call, None) |
||||
if rpc_state is None: |
||||
return |
||||
|
||||
sequence_number = rpc_state.sequence_number |
||||
rpc_state.sequence_number += 1 |
||||
if event.bytes is None: |
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, sequence_number, |
||||
base_interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None, |
||||
None, None) |
||||
else: |
||||
call.read(call) |
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, sequence_number, |
||||
base_interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None, |
||||
None, rpc_state.deserializer(event.bytes), None) |
||||
|
||||
self._rear_link.accept_front_to_back_ticket(ticket) |
||||
|
||||
def _on_write_event(self, event): |
||||
call = event.tag |
||||
rpc_state = self._rpc_states.get(call, None) |
||||
if rpc_state is None: |
||||
return |
||||
|
||||
if rpc_state.write.pending: |
||||
serialized_payload = rpc_state.write.pending.pop(0) |
||||
call.write(serialized_payload, call, 0) |
||||
elif rpc_state.write.high is _common.HighWrite.CLOSED: |
||||
_status(call, rpc_state) |
||||
else: |
||||
rpc_state.write.low = _LowWrite.OPEN |
||||
|
||||
def _on_complete_event(self, event): |
||||
if not event.complete_accepted: |
||||
logging.error('Complete not accepted! %s', (event,)) |
||||
call = event.tag |
||||
rpc_state = self._rpc_states.pop(call, None) |
||||
if rpc_state is None: |
||||
return |
||||
|
||||
sequence_number = rpc_state.sequence_number |
||||
rpc_state.sequence_number += 1 |
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, sequence_number, |
||||
base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None, |
||||
None, None, None, None) |
||||
self._rear_link.accept_front_to_back_ticket(ticket) |
||||
|
||||
def _on_finish_event(self, event): |
||||
"""Handle termination of an RPC.""" |
||||
call = event.tag |
||||
rpc_state = self._rpc_states.pop(call, None) |
||||
if rpc_state is None: |
||||
return |
||||
|
||||
code = event.status.code |
||||
if code is _low.Code.OK: |
||||
return |
||||
|
||||
sequence_number = rpc_state.sequence_number |
||||
rpc_state.sequence_number += 1 |
||||
if code is _low.Code.CANCELLED: |
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, sequence_number, |
||||
base_interfaces.FrontToBackTicket.Kind.CANCELLATION, None, None, |
||||
None, None, None) |
||||
elif code is _low.Code.DEADLINE_EXCEEDED: |
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, sequence_number, |
||||
base_interfaces.FrontToBackTicket.Kind.EXPIRATION, None, None, None, |
||||
None, None) |
||||
else: |
||||
# TODO(nathaniel): Better mapping of codes to ticket-categories |
||||
ticket = base_interfaces.FrontToBackTicket( |
||||
call, sequence_number, |
||||
base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None, |
||||
None, None, None, None) |
||||
self._rear_link.accept_front_to_back_ticket(ticket) |
||||
|
||||
def _spin(self, completion_queue, server): |
||||
while True: |
||||
event = completion_queue.get(None) |
||||
|
||||
with self._condition: |
||||
if event.kind is _low.Event.Kind.STOP: |
||||
self._on_stop_event() |
||||
return |
||||
elif self._server is None: |
||||
continue |
||||
elif event.kind is _low.Event.Kind.SERVICE_ACCEPTED: |
||||
self._on_service_acceptance_event(event, server) |
||||
elif event.kind is _low.Event.Kind.READ_ACCEPTED: |
||||
self._on_read_event(event) |
||||
elif event.kind is _low.Event.Kind.WRITE_ACCEPTED: |
||||
self._on_write_event(event) |
||||
elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED: |
||||
self._on_complete_event(event) |
||||
elif event.kind is _low.Event.Kind.FINISH: |
||||
self._on_finish_event(event) |
||||
else: |
||||
logging.error('Illegal event! %s', (event,)) |
||||
|
||||
def _continue(self, call, payload): |
||||
rpc_state = self._rpc_states.get(call, None) |
||||
if rpc_state is None: |
||||
return |
||||
|
||||
_write(call, rpc_state, payload) |
||||
|
||||
def _complete(self, call, payload): |
||||
"""Handle completion of the writes of an RPC.""" |
||||
rpc_state = self._rpc_states.get(call, None) |
||||
if rpc_state is None: |
||||
return |
||||
|
||||
if rpc_state.write.low is _LowWrite.OPEN: |
||||
if payload is None: |
||||
_status(call, rpc_state) |
||||
else: |
||||
_write(call, rpc_state, payload) |
||||
elif rpc_state.write.low is _LowWrite.ACTIVE: |
||||
if payload is not None: |
||||
rpc_state.write.pending.append(rpc_state.serializer(payload)) |
||||
else: |
||||
raise ValueError('Called to complete after having already completed!') |
||||
rpc_state.write.high = _common.HighWrite.CLOSED |
||||
|
||||
def _cancel(self, call): |
||||
call.cancel() |
||||
self._rpc_states.pop(call, None) |
||||
|
||||
def join_rear_link(self, rear_link): |
||||
"""See base_interfaces.ForeLink.join_rear_link for specification.""" |
||||
self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link |
||||
|
||||
def _start(self): |
||||
"""Starts this ForeLink. |
||||
|
||||
This method must be called before attempting to exchange tickets with this |
||||
object. |
||||
""" |
||||
with self._condition: |
||||
address = '[::]:%d' % ( |
||||
0 if self._requested_port is None else self._requested_port) |
||||
self._completion_queue = _low.CompletionQueue() |
||||
if self._root_certificates is None and not self._key_chain_pairs: |
||||
self._server = _low.Server(self._completion_queue) |
||||
self._port = self._server.add_http2_addr(address) |
||||
else: |
||||
server_credentials = _low.ServerCredentials( |
||||
self._root_certificates, self._key_chain_pairs, False) |
||||
self._server = _low.Server(self._completion_queue) |
||||
self._port = self._server.add_secure_http2_addr( |
||||
address, server_credentials) |
||||
self._server.start() |
||||
|
||||
self._server.service(None) |
||||
|
||||
self._pool.submit(self._spin, self._completion_queue, self._server) |
||||
self._spinning = True |
||||
|
||||
return self |
||||
|
||||
# TODO(nathaniel): Expose graceful-shutdown semantics in which this object |
||||
# enters a state in which it finishes ongoing RPCs but refuses new ones. |
||||
def _stop(self): |
||||
"""Stops this ForeLink. |
||||
|
||||
This method must be called for proper termination of this object, and no |
||||
attempts to exchange tickets with this object may be made after this method |
||||
has been called. |
||||
""" |
||||
with self._condition: |
||||
self._server.stop() |
||||
# TODO(nathaniel): Yep, this is weird. Deleting a server shouldn't have a |
||||
# behaviorally significant side-effect. |
||||
self._server = None |
||||
self._completion_queue.stop() |
||||
|
||||
while self._spinning: |
||||
self._condition.wait() |
||||
|
||||
self._port = None |
||||
|
||||
def __enter__(self): |
||||
"""See activated.Activated.__enter__ for specification.""" |
||||
return self._start() |
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): |
||||
"""See activated.Activated.__exit__ for specification.""" |
||||
self._stop() |
||||
return False |
||||
|
||||
def start(self): |
||||
"""See activated.Activated.start for specification.""" |
||||
return self._start() |
||||
|
||||
def stop(self): |
||||
"""See activated.Activated.stop for specification.""" |
||||
self._stop() |
||||
|
||||
def port(self): |
||||
"""Identifies the port on which this ForeLink is servicing RPCs. |
||||
|
||||
Returns: |
||||
The number of the port on which this ForeLink is servicing RPCs, or None |
||||
if this ForeLink is not currently activated and servicing RPCs. |
||||
""" |
||||
with self._condition: |
||||
return self._port |
||||
|
||||
def accept_back_to_front_ticket(self, ticket): |
||||
"""See base_interfaces.ForeLink.accept_back_to_front_ticket for spec.""" |
||||
with self._condition: |
||||
if self._server is None: |
||||
return |
||||
|
||||
if ticket.kind is base_interfaces.BackToFrontTicket.Kind.CONTINUATION: |
||||
self._continue(ticket.operation_id, ticket.payload) |
||||
elif ticket.kind is base_interfaces.BackToFrontTicket.Kind.COMPLETION: |
||||
self._complete(ticket.operation_id, ticket.payload) |
||||
else: |
||||
self._cancel(ticket.operation_id) |
@ -1,395 +0,0 @@ |
||||
# 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. |
||||
|
||||
"""The RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire.""" |
||||
|
||||
import enum |
||||
import logging |
||||
import threading |
||||
import time |
||||
|
||||
from grpc._adapter import _common |
||||
from grpc._adapter import _intermediary_low as _low |
||||
from grpc.framework.base import interfaces as base_interfaces |
||||
from grpc.framework.base import null |
||||
from grpc.framework.foundation import activated |
||||
from grpc.framework.foundation import logging_pool |
||||
|
||||
_THREAD_POOL_SIZE = 10 |
||||
|
||||
_INVOCATION_EVENT_KINDS = ( |
||||
_low.Event.Kind.METADATA_ACCEPTED, |
||||
_low.Event.Kind.FINISH |
||||
) |
||||
|
||||
|
||||
@enum.unique |
||||
class _LowWrite(enum.Enum): |
||||
"""The possible categories of low-level write state.""" |
||||
|
||||
OPEN = 'OPEN' |
||||
ACTIVE = 'ACTIVE' |
||||
CLOSED = 'CLOSED' |
||||
|
||||
|
||||
class _RPCState(object): |
||||
"""The full state of any tracked RPC. |
||||
|
||||
Attributes: |
||||
call: The _low.Call object for the RPC. |
||||
outstanding: The set of Event.Kind values describing expected future events |
||||
for the RPC. |
||||
active: A boolean indicating whether or not the RPC is active. |
||||
common: An _common.RPCState describing additional state for the RPC. |
||||
""" |
||||
|
||||
def __init__(self, call, outstanding, active, common): |
||||
self.call = call |
||||
self.outstanding = outstanding |
||||
self.active = active |
||||
self.common = common |
||||
|
||||
|
||||
def _write(operation_id, call, outstanding, write_state, serialized_payload): |
||||
if write_state.low is _LowWrite.OPEN: |
||||
call.write(serialized_payload, operation_id, 0) |
||||
outstanding.add(_low.Event.Kind.WRITE_ACCEPTED) |
||||
write_state.low = _LowWrite.ACTIVE |
||||
elif write_state.low is _LowWrite.ACTIVE: |
||||
write_state.pending.append(serialized_payload) |
||||
else: |
||||
raise ValueError('Write attempted after writes completed!') |
||||
|
||||
|
||||
class RearLink(base_interfaces.RearLink, activated.Activated): |
||||
"""An invocation-side bridge between RPC Framework and the C-ish _low code.""" |
||||
|
||||
def __init__( |
||||
self, host, port, pool, request_serializers, response_deserializers, |
||||
secure, root_certificates, private_key, certificate_chain, |
||||
metadata_transformer=None, server_host_override=None): |
||||
"""Constructor. |
||||
|
||||
Args: |
||||
host: The host to which to connect for RPC service. |
||||
port: The port to which to connect for RPC service. |
||||
pool: A thread pool. |
||||
request_serializers: A dict from RPC method names to request object |
||||
serializer behaviors. |
||||
response_deserializers: A dict from RPC method names to response object |
||||
deserializer behaviors. |
||||
secure: A boolean indicating whether or not to use a secure connection. |
||||
root_certificates: The PEM-encoded root certificates or None to ask for |
||||
them to be retrieved from a default location. |
||||
private_key: The PEM-encoded private key to use or None if no private |
||||
key should be used. |
||||
certificate_chain: The PEM-encoded certificate chain to use or None if |
||||
no certificate chain should be used. |
||||
metadata_transformer: A function that given a metadata object produces |
||||
another metadata to be used in the underlying communication on the |
||||
wire. |
||||
server_host_override: (For testing only) the target name used for SSL |
||||
host name checking. |
||||
""" |
||||
self._condition = threading.Condition() |
||||
self._host = host |
||||
self._port = port |
||||
self._pool = pool |
||||
self._request_serializers = request_serializers |
||||
self._response_deserializers = response_deserializers |
||||
|
||||
self._fore_link = null.NULL_FORE_LINK |
||||
self._completion_queue = None |
||||
self._channel = None |
||||
self._rpc_states = {} |
||||
self._spinning = False |
||||
if secure: |
||||
self._client_credentials = _low.ClientCredentials( |
||||
root_certificates, private_key, certificate_chain) |
||||
else: |
||||
self._client_credentials = None |
||||
self._root_certificates = root_certificates |
||||
self._private_key = private_key |
||||
self._certificate_chain = certificate_chain |
||||
self._metadata_transformer = metadata_transformer |
||||
self._server_host_override = server_host_override |
||||
|
||||
def _on_write_event(self, operation_id, event, rpc_state): |
||||
if event.write_accepted: |
||||
if rpc_state.common.write.pending: |
||||
rpc_state.call.write( |
||||
rpc_state.common.write.pending.pop(0), operation_id, 0) |
||||
rpc_state.outstanding.add(_low.Event.Kind.WRITE_ACCEPTED) |
||||
elif rpc_state.common.write.high is _common.HighWrite.CLOSED: |
||||
rpc_state.call.complete(operation_id) |
||||
rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED) |
||||
rpc_state.common.write.low = _LowWrite.CLOSED |
||||
else: |
||||
rpc_state.common.write.low = _LowWrite.OPEN |
||||
else: |
||||
logging.error('RPC write not accepted! Event: %s', (event,)) |
||||
rpc_state.active = False |
||||
ticket = base_interfaces.BackToFrontTicket( |
||||
operation_id, rpc_state.common.sequence_number, |
||||
base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None) |
||||
rpc_state.common.sequence_number += 1 |
||||
self._fore_link.accept_back_to_front_ticket(ticket) |
||||
|
||||
def _on_read_event(self, operation_id, event, rpc_state): |
||||
if event.bytes is not None: |
||||
rpc_state.call.read(operation_id) |
||||
rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED) |
||||
|
||||
ticket = base_interfaces.BackToFrontTicket( |
||||
operation_id, rpc_state.common.sequence_number, |
||||
base_interfaces.BackToFrontTicket.Kind.CONTINUATION, |
||||
rpc_state.common.deserializer(event.bytes)) |
||||
rpc_state.common.sequence_number += 1 |
||||
self._fore_link.accept_back_to_front_ticket(ticket) |
||||
|
||||
def _on_complete_event(self, operation_id, event, rpc_state): |
||||
if not event.complete_accepted: |
||||
logging.error('RPC complete not accepted! Event: %s', (event,)) |
||||
rpc_state.active = False |
||||
ticket = base_interfaces.BackToFrontTicket( |
||||
operation_id, rpc_state.common.sequence_number, |
||||
base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None) |
||||
rpc_state.common.sequence_number += 1 |
||||
self._fore_link.accept_back_to_front_ticket(ticket) |
||||
|
||||
# TODO(nathaniel): Metadata support. |
||||
def _on_metadata_event(self, operation_id, event, rpc_state): # pylint: disable=unused-argument |
||||
rpc_state.call.read(operation_id) |
||||
rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED) |
||||
|
||||
def _on_finish_event(self, operation_id, event, rpc_state): |
||||
"""Handle termination of an RPC.""" |
||||
# TODO(nathaniel): Cover all statuses. |
||||
if event.status.code is _low.Code.OK: |
||||
kind = base_interfaces.BackToFrontTicket.Kind.COMPLETION |
||||
elif event.status.code is _low.Code.CANCELLED: |
||||
kind = base_interfaces.BackToFrontTicket.Kind.CANCELLATION |
||||
elif event.status.code is _low.Code.DEADLINE_EXCEEDED: |
||||
kind = base_interfaces.BackToFrontTicket.Kind.EXPIRATION |
||||
else: |
||||
kind = base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE |
||||
ticket = base_interfaces.BackToFrontTicket( |
||||
operation_id, rpc_state.common.sequence_number, kind, None) |
||||
rpc_state.common.sequence_number += 1 |
||||
self._fore_link.accept_back_to_front_ticket(ticket) |
||||
|
||||
def _spin(self, completion_queue): |
||||
while True: |
||||
event = completion_queue.get(None) |
||||
operation_id = event.tag |
||||
|
||||
with self._condition: |
||||
rpc_state = self._rpc_states[operation_id] |
||||
rpc_state.outstanding.remove(event.kind) |
||||
if rpc_state.active and self._completion_queue is not None: |
||||
if event.kind is _low.Event.Kind.WRITE_ACCEPTED: |
||||
self._on_write_event(operation_id, event, rpc_state) |
||||
elif event.kind is _low.Event.Kind.METADATA_ACCEPTED: |
||||
self._on_metadata_event(operation_id, event, rpc_state) |
||||
elif event.kind is _low.Event.Kind.READ_ACCEPTED: |
||||
self._on_read_event(operation_id, event, rpc_state) |
||||
elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED: |
||||
self._on_complete_event(operation_id, event, rpc_state) |
||||
elif event.kind is _low.Event.Kind.FINISH: |
||||
self._on_finish_event(operation_id, event, rpc_state) |
||||
else: |
||||
logging.error('Illegal RPC event! %s', (event,)) |
||||
|
||||
if not rpc_state.outstanding: |
||||
self._rpc_states.pop(operation_id) |
||||
if not self._rpc_states: |
||||
self._spinning = False |
||||
self._condition.notify_all() |
||||
return |
||||
|
||||
def _invoke(self, operation_id, name, high_state, payload, timeout): |
||||
"""Invoke an RPC. |
||||
|
||||
Args: |
||||
operation_id: Any object to be used as an operation ID for the RPC. |
||||
name: The RPC method name. |
||||
high_state: A _common.HighWrite value representing the "high write state" |
||||
of the RPC. |
||||
payload: A payload object for the RPC or None if no payload was given at |
||||
invocation-time. |
||||
timeout: A duration of time in seconds to allow for the RPC. |
||||
""" |
||||
request_serializer = self._request_serializers[name] |
||||
call = _low.Call(self._channel, self._completion_queue, name, self._host, time.time() + timeout) |
||||
if self._metadata_transformer is not None: |
||||
metadata = self._metadata_transformer([]) |
||||
for metadata_key, metadata_value in metadata: |
||||
call.add_metadata(metadata_key, metadata_value) |
||||
call.invoke(self._completion_queue, operation_id, operation_id) |
||||
outstanding = set(_INVOCATION_EVENT_KINDS) |
||||
|
||||
if payload is None: |
||||
if high_state is _common.HighWrite.CLOSED: |
||||
call.complete(operation_id) |
||||
low_state = _LowWrite.CLOSED |
||||
outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED) |
||||
else: |
||||
low_state = _LowWrite.OPEN |
||||
else: |
||||
serialized_payload = request_serializer(payload) |
||||
call.write(serialized_payload, operation_id, 0) |
||||
outstanding.add(_low.Event.Kind.WRITE_ACCEPTED) |
||||
low_state = _LowWrite.ACTIVE |
||||
|
||||
write_state = _common.WriteState(low_state, high_state, []) |
||||
common_state = _common.CommonRPCState( |
||||
write_state, 0, self._response_deserializers[name], request_serializer) |
||||
self._rpc_states[operation_id] = _RPCState( |
||||
call, outstanding, True, common_state) |
||||
|
||||
if not self._spinning: |
||||
self._pool.submit(self._spin, self._completion_queue) |
||||
self._spinning = True |
||||
|
||||
def _commence(self, operation_id, name, payload, timeout): |
||||
self._invoke(operation_id, name, _common.HighWrite.OPEN, payload, timeout) |
||||
|
||||
def _continue(self, operation_id, payload): |
||||
rpc_state = self._rpc_states.get(operation_id, None) |
||||
if rpc_state is None or not rpc_state.active: |
||||
return |
||||
|
||||
_write( |
||||
operation_id, rpc_state.call, rpc_state.outstanding, |
||||
rpc_state.common.write, rpc_state.common.serializer(payload)) |
||||
|
||||
def _complete(self, operation_id, payload): |
||||
"""Close writes associated with an ongoing RPC. |
||||
|
||||
Args: |
||||
operation_id: Any object being use as an operation ID for the RPC. |
||||
payload: A payload object for the RPC (and thus the last payload object |
||||
for the RPC) or None if no payload was given along with the instruction |
||||
to indicate the end of writes for the RPC. |
||||
""" |
||||
rpc_state = self._rpc_states.get(operation_id, None) |
||||
if rpc_state is None or not rpc_state.active: |
||||
return |
||||
|
||||
write_state = rpc_state.common.write |
||||
if payload is None: |
||||
if write_state.low is _LowWrite.OPEN: |
||||
rpc_state.call.complete(operation_id) |
||||
rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED) |
||||
write_state.low = _LowWrite.CLOSED |
||||
else: |
||||
_write( |
||||
operation_id, rpc_state.call, rpc_state.outstanding, write_state, |
||||
rpc_state.common.serializer(payload)) |
||||
write_state.high = _common.HighWrite.CLOSED |
||||
|
||||
def _entire(self, operation_id, name, payload, timeout): |
||||
self._invoke(operation_id, name, _common.HighWrite.CLOSED, payload, timeout) |
||||
|
||||
def _cancel(self, operation_id): |
||||
rpc_state = self._rpc_states.get(operation_id, None) |
||||
if rpc_state is not None and rpc_state.active: |
||||
rpc_state.call.cancel() |
||||
rpc_state.active = False |
||||
|
||||
def join_fore_link(self, fore_link): |
||||
"""See base_interfaces.RearLink.join_fore_link for specification.""" |
||||
with self._condition: |
||||
self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link |
||||
|
||||
def _start(self): |
||||
"""Starts this RearLink. |
||||
|
||||
This method must be called before attempting to exchange tickets with this |
||||
object. |
||||
""" |
||||
with self._condition: |
||||
self._completion_queue = _low.CompletionQueue() |
||||
self._channel = _low.Channel( |
||||
'%s:%d' % (self._host, self._port), self._client_credentials, |
||||
server_host_override=self._server_host_override) |
||||
return self |
||||
|
||||
def _stop(self): |
||||
"""Stops this RearLink. |
||||
|
||||
This method must be called for proper termination of this object, and no |
||||
attempts to exchange tickets with this object may be made after this method |
||||
has been called. |
||||
""" |
||||
with self._condition: |
||||
self._completion_queue.stop() |
||||
self._completion_queue = None |
||||
|
||||
while self._spinning: |
||||
self._condition.wait() |
||||
|
||||
def __enter__(self): |
||||
"""See activated.Activated.__enter__ for specification.""" |
||||
return self._start() |
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): |
||||
"""See activated.Activated.__exit__ for specification.""" |
||||
self._stop() |
||||
return False |
||||
|
||||
def start(self): |
||||
"""See activated.Activated.start for specification.""" |
||||
return self._start() |
||||
|
||||
def stop(self): |
||||
"""See activated.Activated.stop for specification.""" |
||||
self._stop() |
||||
|
||||
def accept_front_to_back_ticket(self, ticket): |
||||
"""See base_interfaces.RearLink.accept_front_to_back_ticket for spec.""" |
||||
with self._condition: |
||||
if self._completion_queue is None: |
||||
return |
||||
|
||||
if ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT: |
||||
self._commence( |
||||
ticket.operation_id, ticket.name, ticket.payload, ticket.timeout) |
||||
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CONTINUATION: |
||||
self._continue(ticket.operation_id, ticket.payload) |
||||
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMPLETION: |
||||
self._complete(ticket.operation_id, ticket.payload) |
||||
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.ENTIRE: |
||||
self._entire( |
||||
ticket.operation_id, ticket.name, ticket.payload, ticket.timeout) |
||||
elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CANCELLATION: |
||||
self._cancel(ticket.operation_id) |
||||
else: |
||||
# NOTE(nathaniel): All other categories are treated as cancellation. |
||||
self._cancel(ticket.operation_id) |
@ -1,35 +0,0 @@ |
||||
# 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. |
||||
|
||||
import warnings |
||||
|
||||
warnings.simplefilter('always', DeprecationWarning) |
||||
warnings.warn('the alpha API (includes this package) is deprecated, ' |
||||
'unmaintained, and no longer tested. Please migrate to the beta ' |
||||
'API.', DeprecationWarning, stacklevel=2) |
@ -1,262 +0,0 @@ |
||||
# 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. |
||||
|
||||
"""Entry points into GRPC.""" |
||||
|
||||
import threading |
||||
|
||||
from grpc._adapter import fore as _fore |
||||
from grpc._adapter import rear as _rear |
||||
from grpc.framework.alpha import _face_utilities |
||||
from grpc.framework.alpha import _reexport |
||||
from grpc.framework.alpha import interfaces |
||||
from grpc.framework.base import implementations as _base_implementations |
||||
from grpc.framework.base import util as _base_utilities |
||||
from grpc.framework.face import implementations as _face_implementations |
||||
from grpc.framework.foundation import logging_pool |
||||
|
||||
_DEFAULT_THREAD_POOL_SIZE = 8 |
||||
_ONE_DAY_IN_SECONDS = 24 * 60 * 60 |
||||
|
||||
|
||||
class _Server(interfaces.Server): |
||||
|
||||
def __init__( |
||||
self, breakdown, port, private_key, certificate_chain, |
||||
thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): |
||||
self._lock = threading.Lock() |
||||
self._breakdown = breakdown |
||||
self._port = port |
||||
if private_key is None or certificate_chain is None: |
||||
self._key_chain_pairs = () |
||||
else: |
||||
self._key_chain_pairs = ((private_key, certificate_chain),) |
||||
|
||||
self._pool_size = thread_pool_size |
||||
self._pool = None |
||||
self._back = None |
||||
self._fore_link = None |
||||
|
||||
def _start(self): |
||||
with self._lock: |
||||
if self._pool is None: |
||||
self._pool = logging_pool.pool(self._pool_size) |
||||
servicer = _face_implementations.servicer( |
||||
self._pool, self._breakdown.implementations, None) |
||||
self._back = _base_implementations.back_link( |
||||
servicer, self._pool, self._pool, self._pool, _ONE_DAY_IN_SECONDS, |
||||
_ONE_DAY_IN_SECONDS) |
||||
self._fore_link = _fore.ForeLink( |
||||
self._pool, self._breakdown.request_deserializers, |
||||
self._breakdown.response_serializers, None, self._key_chain_pairs, |
||||
port=self._port) |
||||
self._back.join_fore_link(self._fore_link) |
||||
self._fore_link.join_rear_link(self._back) |
||||
self._fore_link.start() |
||||
else: |
||||
raise ValueError('Server currently running!') |
||||
|
||||
def _stop(self): |
||||
with self._lock: |
||||
if self._pool is None: |
||||
raise ValueError('Server not running!') |
||||
else: |
||||
self._fore_link.stop() |
||||
_base_utilities.wait_for_idle(self._back) |
||||
self._pool.shutdown(wait=True) |
||||
self._fore_link = None |
||||
self._back = None |
||||
self._pool = None |
||||
|
||||
def __enter__(self): |
||||
self._start() |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): |
||||
self._stop() |
||||
return False |
||||
|
||||
def start(self): |
||||
self._start() |
||||
|
||||
def stop(self): |
||||
self._stop() |
||||
|
||||
def port(self): |
||||
with self._lock: |
||||
return self._fore_link.port() |
||||
|
||||
|
||||
class _Stub(interfaces.Stub): |
||||
|
||||
def __init__( |
||||
self, breakdown, host, port, secure, root_certificates, private_key, |
||||
certificate_chain, metadata_transformer=None, server_host_override=None, |
||||
thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): |
||||
self._lock = threading.Lock() |
||||
self._breakdown = breakdown |
||||
self._host = host |
||||
self._port = port |
||||
self._secure = secure |
||||
self._root_certificates = root_certificates |
||||
self._private_key = private_key |
||||
self._certificate_chain = certificate_chain |
||||
self._metadata_transformer = metadata_transformer |
||||
self._server_host_override = server_host_override |
||||
|
||||
self._pool_size = thread_pool_size |
||||
self._pool = None |
||||
self._front = None |
||||
self._rear_link = None |
||||
self._understub = None |
||||
|
||||
def __enter__(self): |
||||
with self._lock: |
||||
if self._pool is None: |
||||
self._pool = logging_pool.pool(self._pool_size) |
||||
self._front = _base_implementations.front_link( |
||||
self._pool, self._pool, self._pool) |
||||
self._rear_link = _rear.RearLink( |
||||
self._host, self._port, self._pool, |
||||
self._breakdown.request_serializers, |
||||
self._breakdown.response_deserializers, self._secure, |
||||
self._root_certificates, self._private_key, self._certificate_chain, |
||||
metadata_transformer=self._metadata_transformer, |
||||
server_host_override=self._server_host_override) |
||||
self._front.join_rear_link(self._rear_link) |
||||
self._rear_link.join_fore_link(self._front) |
||||
self._rear_link.start() |
||||
self._understub = _face_implementations.dynamic_stub( |
||||
self._breakdown.face_cardinalities, self._front, self._pool, '') |
||||
else: |
||||
raise ValueError('Tried to __enter__ already-__enter__ed Stub!') |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): |
||||
with self._lock: |
||||
if self._pool is None: |
||||
raise ValueError('Tried to __exit__ non-__enter__ed Stub!') |
||||
else: |
||||
self._rear_link.stop() |
||||
_base_utilities.wait_for_idle(self._front) |
||||
self._pool.shutdown(wait=True) |
||||
self._rear_link = None |
||||
self._front = None |
||||
self._pool = None |
||||
self._understub = None |
||||
return False |
||||
|
||||
def __getattr__(self, attr): |
||||
with self._lock: |
||||
if self._pool is None: |
||||
raise ValueError('Tried to __getattr__ non-__enter__ed Stub!') |
||||
else: |
||||
method_cardinality = self._breakdown.cardinalities.get(attr) |
||||
underlying_attr = getattr( |
||||
self._understub, self._breakdown.qualified_names.get(attr), None) |
||||
if method_cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
return _reexport.unary_unary_sync_async(underlying_attr) |
||||
elif method_cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
return lambda request, timeout: _reexport.cancellable_iterator( |
||||
underlying_attr(request, timeout)) |
||||
elif method_cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
return _reexport.stream_unary_sync_async(underlying_attr) |
||||
elif method_cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
return lambda request_iterator, timeout: ( |
||||
_reexport.cancellable_iterator(underlying_attr( |
||||
request_iterator, timeout))) |
||||
else: |
||||
raise AttributeError(attr) |
||||
|
||||
|
||||
def stub( |
||||
service_name, methods, host, port, metadata_transformer=None, secure=False, |
||||
root_certificates=None, private_key=None, certificate_chain=None, |
||||
server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): |
||||
"""Constructs an interfaces.Stub. |
||||
|
||||
Args: |
||||
service_name: The package-qualified full name of the service. |
||||
methods: A dictionary from RPC method name to |
||||
interfaces.RpcMethodInvocationDescription describing the RPCs to be |
||||
supported by the created stub. The RPC method names in the dictionary are |
||||
not qualified by the service name or decorated in any other way. |
||||
host: The host to which to connect for RPC service. |
||||
port: The port to which to connect for RPC service. |
||||
metadata_transformer: A callable that given a metadata object produces |
||||
another metadata object to be used in the underlying communication on the |
||||
wire. |
||||
secure: Whether or not to construct the stub with a secure connection. |
||||
root_certificates: The PEM-encoded root certificates or None to ask for |
||||
them to be retrieved from a default location. |
||||
private_key: The PEM-encoded private key to use or None if no private key |
||||
should be used. |
||||
certificate_chain: The PEM-encoded certificate chain to use or None if no |
||||
certificate chain should be used. |
||||
server_host_override: (For testing only) the target name used for SSL |
||||
host name checking. |
||||
thread_pool_size: The maximum number of threads to allow in the backing |
||||
thread pool. |
||||
|
||||
Returns: |
||||
An interfaces.Stub affording RPC invocation. |
||||
""" |
||||
breakdown = _face_utilities.break_down_invocation(service_name, methods) |
||||
return _Stub( |
||||
breakdown, host, port, secure, root_certificates, private_key, |
||||
certificate_chain, server_host_override=server_host_override, |
||||
metadata_transformer=metadata_transformer, |
||||
thread_pool_size=thread_pool_size) |
||||
|
||||
|
||||
def server( |
||||
service_name, methods, port, private_key=None, certificate_chain=None, |
||||
thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): |
||||
"""Constructs an interfaces.Server. |
||||
|
||||
Args: |
||||
service_name: The package-qualified full name of the service. |
||||
methods: A dictionary from RPC method name to |
||||
interfaces.RpcMethodServiceDescription describing the RPCs to |
||||
be serviced by the created server. The RPC method names in the dictionary |
||||
are not qualified by the service name or decorated in any other way. |
||||
port: The port on which to serve or zero to ask for a port to be |
||||
automatically selected. |
||||
private_key: A pem-encoded private key, or None for an insecure server. |
||||
certificate_chain: A pem-encoded certificate chain, or None for an insecure |
||||
server. |
||||
thread_pool_size: The maximum number of threads to allow in the backing |
||||
thread pool. |
||||
|
||||
Returns: |
||||
An interfaces.Server that will serve secure traffic. |
||||
""" |
||||
breakdown = _face_utilities.break_down_service(service_name, methods) |
||||
return _Server(breakdown, port, private_key, certificate_chain, |
||||
thread_pool_size=thread_pool_size) |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue